mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-11-06 06:27:32 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
310
python/psutil/CREDITS
Normal file
310
python/psutil/CREDITS
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
Intro
|
||||
=====
|
||||
|
||||
I would like to recognize some of the people who have been instrumental in the
|
||||
development of psutil.
|
||||
I'm sure I'm forgetting some people (feel free to email me), but here is a
|
||||
short list.
|
||||
It's modeled after the Linux CREDITS file where the fields are:
|
||||
name (N), e-mail (E), web-address (W), country (C), description (D), (I) issues
|
||||
(issue tracker is at https://github.com/giampaolo/psutil/issues).
|
||||
Really thanks to all of you.
|
||||
|
||||
- Giampaolo
|
||||
|
||||
Author
|
||||
======
|
||||
|
||||
N: Giampaolo Rodola'
|
||||
C: Italy
|
||||
E: g.rodola@gmail.com
|
||||
W: http://grodola.blogspot.com/
|
||||
|
||||
Contributors
|
||||
============
|
||||
|
||||
N: Jay Loden
|
||||
C: NJ, USA
|
||||
E: jloden@gmail.com
|
||||
D: original co-author, initial design/bootstrap and occasional bug fixes
|
||||
W: http://www.jayloden.com
|
||||
|
||||
N: Jeremy Whitlock
|
||||
E: jcscoobyrs@gmail.com
|
||||
D: great help with OSX C development.
|
||||
I: 125, 150, 174, 206
|
||||
|
||||
N: wj32
|
||||
E: wj32.64@gmail.com
|
||||
D: process username() and get_connections() on Windows
|
||||
I: 114, 115
|
||||
|
||||
N: Yan Raber
|
||||
C: Bologna, Italy
|
||||
E: yanraber@gmail.com
|
||||
D: help on Windows development (initial version of Process.username())
|
||||
|
||||
N: Justin Venus
|
||||
E: justin.venus@gmail.com
|
||||
D: Solaris support
|
||||
I: 18
|
||||
|
||||
N: Dave Daeschler
|
||||
C: USA
|
||||
E: david.daeschler@gmail.com
|
||||
W: http://daviddaeschler.com
|
||||
D: some contributions to initial design/bootstrap plus occasional bug fixing
|
||||
I: 522, 536
|
||||
|
||||
N: cjgohlke
|
||||
E: cjgohlke@gmail.com
|
||||
D: Windows 64 bit support
|
||||
I: 107
|
||||
|
||||
N: Jeffery Kline
|
||||
E: jeffery.kline@gmail.com
|
||||
I: 130
|
||||
|
||||
N: Grabriel Monnerat
|
||||
E: gabrielmonnerat@gmail.com
|
||||
I: 146
|
||||
|
||||
N: Philip Roberts
|
||||
E: philip.roberts@gmail.com
|
||||
I: 168
|
||||
|
||||
N: jcscoobyrs
|
||||
E: jcscoobyrs@gmail.com
|
||||
I: 125
|
||||
|
||||
N: Sandro Tosi
|
||||
E: sandro.tosi@gmail.com
|
||||
I: 200, 201
|
||||
|
||||
N: Andrew Colin
|
||||
E: andrew.colin@gmail.com
|
||||
I: 248
|
||||
|
||||
N: Amoser
|
||||
E: amoser@google.com
|
||||
I: 266, 267, 340
|
||||
|
||||
N: Matthew Grant
|
||||
E: matthewgrant5@gmail.com
|
||||
I: 271
|
||||
|
||||
N: oweidner
|
||||
E: oweidner@cct.lsu.edu
|
||||
I: 275
|
||||
|
||||
N: Tarek Ziade
|
||||
E: ziade.tarek
|
||||
I: 281
|
||||
|
||||
N: Luca Cipriani
|
||||
C: Turin, Italy
|
||||
E: luca.opensource@gmail.com
|
||||
I: 278
|
||||
|
||||
N: Maciej Lach,
|
||||
E: maciej.lach@gmail.com
|
||||
I: 294
|
||||
|
||||
N: James Pye
|
||||
E: james.pye@gmail.com
|
||||
I: 305, 306
|
||||
|
||||
N: Stanchev Emil
|
||||
E: stanchev.emil
|
||||
I: 314
|
||||
|
||||
N: Kim Gräsman
|
||||
E: kim.grasman@gmail.com
|
||||
D: ...also kindly donated some money.
|
||||
I: 316
|
||||
|
||||
N: Riccardo Murri
|
||||
C: Italy
|
||||
I: 318
|
||||
|
||||
N: Florent Xicluna
|
||||
E: florent.xicluna@gmail.com
|
||||
I: 319
|
||||
|
||||
N: Michal Spondr
|
||||
E: michal.spondr
|
||||
I: 313
|
||||
|
||||
N: Jean Sebastien
|
||||
E: dumbboules@gmail.com
|
||||
I: 344
|
||||
|
||||
N: Rob Smith
|
||||
W: http://www.kormoc.com/
|
||||
I: 341
|
||||
|
||||
N: Youngsik Kim
|
||||
W: https://plus.google.com/101320747613749824490/
|
||||
I: 317
|
||||
|
||||
N: Gregory Szorc
|
||||
W: https://plus.google.com/116873264322260110710/posts
|
||||
I: 323
|
||||
|
||||
N: André Oriani
|
||||
E: aoriani@gmail.com
|
||||
I: 361
|
||||
|
||||
N: clackwell
|
||||
E: clackwell@gmail.com
|
||||
I: 356
|
||||
|
||||
N: m.malycha
|
||||
E: m.malycha@gmail.com
|
||||
I: 351
|
||||
|
||||
N: John Baldwin
|
||||
E: jhb@FreeBSD.org
|
||||
I: 370
|
||||
|
||||
N: Jan Beich
|
||||
E: jbeich@tormail.org
|
||||
I: 325
|
||||
|
||||
N: floppymaster
|
||||
E: floppymaster@gmail.com
|
||||
I: 380
|
||||
|
||||
N: Arfrever.FTA
|
||||
E: Arfrever.FTA@gmail.com
|
||||
I: 369, 404
|
||||
|
||||
N: danudey
|
||||
E: danudey@gmail.com
|
||||
I: 386
|
||||
|
||||
N: Adrien Fallou
|
||||
I: 224
|
||||
|
||||
N: Gisle Vanem
|
||||
E: gisle.vanem@gmail.com
|
||||
I: 411
|
||||
|
||||
N: thepyr0
|
||||
E: thepyr0@gmail.com
|
||||
I: 414
|
||||
|
||||
N: John Pankov
|
||||
E: john.pankov@gmail.com
|
||||
I: 435
|
||||
|
||||
N: Matt Good
|
||||
W: http://matt-good.net/
|
||||
I: 438
|
||||
|
||||
N: Ulrich Klank
|
||||
E: ulrich.klank@scitics.de
|
||||
I: 448
|
||||
|
||||
N: Josiah Carlson
|
||||
E: josiah.carlson@gmail.com
|
||||
I: 451, 452
|
||||
|
||||
N: Raymond Hettinger
|
||||
D: namedtuple and lru_cache backward compatible implementations.
|
||||
|
||||
N: Jason Kirtland
|
||||
D: backward compatible implementation of collections.defaultdict.
|
||||
|
||||
M: Ken Seeho
|
||||
D: @cached_property decorator
|
||||
|
||||
N: crusaderky
|
||||
E: crusaderky@gmail.com
|
||||
I: 470, 477
|
||||
|
||||
E: alex@mroja.net
|
||||
I: 471
|
||||
|
||||
N: Gautam Singh
|
||||
E: gautam.singh@gmail.com
|
||||
I: 466
|
||||
|
||||
E: lhn@hupfeldtit.dk
|
||||
I: 476, 479
|
||||
|
||||
N: Francois Charron
|
||||
E: francois.charron.1@gmail.com
|
||||
I: 474
|
||||
|
||||
N: Naveed Roudsari
|
||||
E: naveed.roudsari@gmail.com
|
||||
I: 421
|
||||
|
||||
N: Alexander Grothe
|
||||
E: Alexander.Grothe@gmail.com
|
||||
I: 497
|
||||
|
||||
N: Szigeti Gabor Niif
|
||||
E: szigeti.gabor.niif@gmail.com
|
||||
I: 446
|
||||
|
||||
N: msabramo
|
||||
E: msabramo@gmail.com
|
||||
I: 492
|
||||
|
||||
N: Jeff Tang
|
||||
W: https://github.com/mrjefftang
|
||||
I: 340, 529, 616, 653, 654
|
||||
|
||||
N: Yaolong Huang
|
||||
E: airekans@gmail.com
|
||||
W: http://airekans.github.io/
|
||||
I: 530
|
||||
|
||||
N: Anders Chrigström
|
||||
W: https://github.com/anders-chrigstrom
|
||||
I: 496
|
||||
|
||||
N: spacewander
|
||||
E: spacewanderlzx@gmail.com
|
||||
I: 561
|
||||
|
||||
N: Sylvain Mouquet
|
||||
E: sylvain.mouquet@gmail.com
|
||||
I: 565
|
||||
|
||||
N: karthikrev
|
||||
I: 568
|
||||
|
||||
N: Bruno Binet
|
||||
E: bruno.binet@gmail.com
|
||||
I: 572
|
||||
|
||||
N: Gabi Davar
|
||||
C: Israel
|
||||
W: https://github.com/mindw
|
||||
I: 578, 581, 587
|
||||
|
||||
N: spacewanderlzx
|
||||
C: Guangzhou,China
|
||||
E: spacewanderlzx@gmail.com
|
||||
I: 555
|
||||
|
||||
N: Fabian Groffen
|
||||
I: 611, 618
|
||||
|
||||
N: desbma
|
||||
W: https://github.com/desbma
|
||||
C: France
|
||||
I: 628
|
||||
|
||||
N: John Burnett
|
||||
W: http://www.johnburnett.com/
|
||||
C: Irvine, CA, US
|
||||
I: 614
|
||||
|
||||
N: Árni Már Jónsson
|
||||
E: Reykjavik, Iceland
|
||||
E: https://github.com/arnimarj
|
||||
I: 634
|
||||
1018
python/psutil/HISTORY.rst
Normal file
1018
python/psutil/HISTORY.rst
Normal file
File diff suppressed because it is too large
Load diff
116
python/psutil/INSTALL.rst
Normal file
116
python/psutil/INSTALL.rst
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
============================
|
||||
Installing using pip on UNIX
|
||||
============================
|
||||
|
||||
The easiest way to install psutil on UNIX is by using pip (but first you might
|
||||
need to install python header files; see later).
|
||||
First install pip::
|
||||
|
||||
$ wget https://bootstrap.pypa.io/get-pip.py
|
||||
$ python get-pip.py
|
||||
|
||||
...then run::
|
||||
|
||||
$ pip install psutil
|
||||
|
||||
You may need to install gcc and python header files first (see later).
|
||||
|
||||
|
||||
=====================
|
||||
Installing on Windows
|
||||
=====================
|
||||
|
||||
Just get the right installer for your Python version and architecture from:
|
||||
https://pypi.python.org/pypi/psutil/#downloads
|
||||
Since wheels installers are also available you may also use pip.
|
||||
|
||||
|
||||
========================================
|
||||
Compiling on Windows using Visual Studio
|
||||
========================================
|
||||
|
||||
In order to compile psutil on Windows you'll need Visual Studio (Mingw32 is
|
||||
no longer supported). You must have the same version of Visual Studio used to compile
|
||||
your installation of Python, that is::
|
||||
|
||||
* Python 2.6: VS 2008
|
||||
* Python 2.7: VS 2008
|
||||
* Python 3.3, 3.4: VS 2010 (you can download it from `MS website <http://www.visualstudio.com/downloads/download-visual-studio-vs#d-2010-express>`_)
|
||||
* Python 3.5: `VS 2015 UP <http://www.visualstudio.com/en-au/news/vs2015-preview-vs>`_
|
||||
|
||||
...then run::
|
||||
|
||||
setup.py build
|
||||
|
||||
...or::
|
||||
|
||||
make.bat build
|
||||
|
||||
Compiling 64 bit versions of Python 2.6 and 2.7 with VS 2008 requires
|
||||
Windows SDK and .NET Framework 3.5 SP1 to be installed first.
|
||||
Once you have those run vcvars64.bat, then compile:
|
||||
http://stackoverflow.com/questions/11072521/
|
||||
|
||||
===================
|
||||
Installing on Linux
|
||||
===================
|
||||
|
||||
gcc is required and so the python headers. They can easily be installed by
|
||||
using the distro package manager. For example, on Debian and Ubuntu::
|
||||
|
||||
$ sudo apt-get install gcc python-dev
|
||||
|
||||
...on Redhat and CentOS::
|
||||
|
||||
$ sudo yum install gcc python-devel
|
||||
|
||||
Once done, you can build/install psutil with::
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
|
||||
==================
|
||||
Installing on OS X
|
||||
==================
|
||||
|
||||
OS X installation from source will require gcc which you can obtain as part of
|
||||
the 'XcodeTools' installer from Apple. Then you can run the standard distutils
|
||||
commands.
|
||||
To build only::
|
||||
|
||||
$ python setup.py build
|
||||
|
||||
To install and build::
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
|
||||
=====================
|
||||
Installing on FreeBSD
|
||||
=====================
|
||||
|
||||
The same compiler used to install Python must be present on the system in order
|
||||
to build modules using distutils. Assuming it is installed, you can build using
|
||||
the standard distutils commands.
|
||||
|
||||
Build only::
|
||||
|
||||
$ python setup.py build
|
||||
|
||||
Install and build::
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
|
||||
========
|
||||
Makefile
|
||||
========
|
||||
|
||||
A makefile is available for both UNIX and Windows (make.bat). It provides
|
||||
some automations for the tasks described above and might be preferred over
|
||||
using setup.py. With it you can::
|
||||
|
||||
$ make install # just install (in --user mode)
|
||||
$ make uninstall # uninstall (needs pip)
|
||||
$ make test # run tests
|
||||
$ make clean # remove installation files
|
||||
27
python/psutil/LICENSE
Normal file
27
python/psutil/LICENSE
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
psutil is distributed under BSD license reproduced below.
|
||||
|
||||
Copyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola'
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the psutil authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
22
python/psutil/MANIFEST.in
Normal file
22
python/psutil/MANIFEST.in
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
include .coveragerc
|
||||
include .git-pre-commit
|
||||
include .git-pre-commit
|
||||
include .gitignore
|
||||
include .travis.yml
|
||||
include CREDITS
|
||||
include HISTORY.rst
|
||||
include INSTALL.rst
|
||||
include LICENSE
|
||||
include make.bat
|
||||
include Makefile
|
||||
include MANIFEST.in
|
||||
include README.rst
|
||||
include setup.py
|
||||
include TODO
|
||||
include tox.ini
|
||||
recursive-exclude docs/_build *
|
||||
recursive-include .appveyor/*
|
||||
recursive-include docs *
|
||||
recursive-include examples *.py
|
||||
recursive-include psutil *.py *.c *.h
|
||||
recursive-include test *.py README*
|
||||
122
python/psutil/Makefile
Normal file
122
python/psutil/Makefile
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Shortcuts for various tasks (UNIX only).
|
||||
# To use a specific Python version run:
|
||||
# $ make install PYTHON=python3.3
|
||||
|
||||
# You can set these variables from the command line.
|
||||
PYTHON = python
|
||||
TSCRIPT = test/test_psutil.py
|
||||
|
||||
all: test
|
||||
|
||||
clean:
|
||||
rm -f `find . -type f -name \*.py[co]`
|
||||
rm -f `find . -type f -name \*.so`
|
||||
rm -f `find . -type f -name .\*~`
|
||||
rm -f `find . -type f -name \*.orig`
|
||||
rm -f `find . -type f -name \*.bak`
|
||||
rm -f `find . -type f -name \*.rej`
|
||||
rm -rf `find . -type d -name __pycache__`
|
||||
rm -rf *.core
|
||||
rm -rf *.egg-info
|
||||
rm -rf *\$testfile*
|
||||
rm -rf .coverage
|
||||
rm -rf .tox
|
||||
rm -rf build
|
||||
rm -rf dist
|
||||
rm -rf docs/_build
|
||||
rm -rf htmlcov
|
||||
|
||||
build: clean
|
||||
$(PYTHON) setup.py build
|
||||
@# copies *.so files in ./psutil directory in order to allow
|
||||
@# "import psutil" when using the interactive interpreter from within
|
||||
@# this directory.
|
||||
$(PYTHON) setup.py build_ext -i
|
||||
|
||||
# useful deps which are nice to have while developing / testing
|
||||
setup-dev-env:
|
||||
python -c "import urllib2; \
|
||||
r = urllib2.urlopen('https://bootstrap.pypa.io/get-pip.py'); \
|
||||
open('/tmp/get-pip.py', 'w').write(r.read());"
|
||||
$(PYTHON) /tmp/get-pip.py --user
|
||||
rm /tmp/get-pip.py
|
||||
$(PYTHON) -m pip install --user --upgrade pip
|
||||
$(PYTHON) -m pip install --user --upgrade \
|
||||
coverage \
|
||||
flake8 \
|
||||
ipaddress \
|
||||
ipdb \
|
||||
mock==1.0.1 \
|
||||
nose \
|
||||
pep8 \
|
||||
pyflakes \
|
||||
sphinx \
|
||||
sphinx-pypi-upload \
|
||||
unittest2 \
|
||||
|
||||
install: build
|
||||
$(PYTHON) setup.py install --user
|
||||
|
||||
uninstall:
|
||||
cd ..; $(PYTHON) -m pip uninstall -y -v psutil
|
||||
|
||||
test: install
|
||||
$(PYTHON) $(TSCRIPT)
|
||||
|
||||
test-process: install
|
||||
$(PYTHON) -m unittest -v test.test_psutil.TestProcess
|
||||
|
||||
test-system: install
|
||||
$(PYTHON) -m unittest -v test.test_psutil.TestSystemAPIs
|
||||
|
||||
test-memleaks: install
|
||||
$(PYTHON) test/test_memory_leaks.py
|
||||
|
||||
# Run a specific test by name; e.g. "make test-by-name disk_" will run
|
||||
# all test methods containing "disk_" in their name.
|
||||
# Requires "pip install nose".
|
||||
test-by-name: install
|
||||
@$(PYTHON) -m nose test/test_psutil.py test/_* --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS))
|
||||
|
||||
# Same as above but for test_memory_leaks.py script.
|
||||
test-memleaks-by-name: install
|
||||
@$(PYTHON) -m nose test/test_memory_leaks.py --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS))
|
||||
|
||||
coverage: install
|
||||
# Note: coverage options are controlled by .coveragerc file
|
||||
rm -rf .coverage htmlcov
|
||||
$(PYTHON) -m coverage run $(TSCRIPT)
|
||||
$(PYTHON) -m coverage report
|
||||
@echo "writing results to htmlcov/index.html"
|
||||
$(PYTHON) -m coverage html
|
||||
$(PYTHON) -m webbrowser -t htmlcov/index.html
|
||||
|
||||
pep8:
|
||||
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m pep8
|
||||
|
||||
pyflakes:
|
||||
@export PYFLAKES_NODOCTEST=1 && \
|
||||
git ls-files | grep \\.py$ | xargs $(PYTHON) -m pyflakes
|
||||
|
||||
flake8:
|
||||
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8
|
||||
|
||||
# Upload source tarball on https://pypi.python.org/pypi/psutil.
|
||||
upload-src: clean
|
||||
$(PYTHON) setup.py sdist upload
|
||||
|
||||
# Build and upload doc on https://pythonhosted.org/psutil/.
|
||||
# Requires "pip install sphinx-pypi-upload".
|
||||
upload-doc:
|
||||
cd docs; make html
|
||||
$(PYTHON) setup.py upload_sphinx --upload-dir=docs/_build/html
|
||||
|
||||
# git-tag a new release
|
||||
git-tag-release:
|
||||
git tag -a release-`python -c "import setup; print(setup.get_version())"` -m `git rev-list HEAD --count`:`git rev-parse --short HEAD`
|
||||
echo "done; now run 'git push --follow-tags' to push the new tag on the remote repo"
|
||||
|
||||
# install GIT pre-commit hook
|
||||
install-git-hooks:
|
||||
ln -sf ../../.git-pre-commit .git/hooks/pre-commit
|
||||
chmod +x .git/hooks/pre-commit
|
||||
434
python/psutil/PKG-INFO
Normal file
434
python/psutil/PKG-INFO
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: psutil
|
||||
Version: 3.1.1
|
||||
Summary: psutil is a cross-platform library for retrieving information onrunning processes and system utilization (CPU, memory, disks, network)in Python.
|
||||
Home-page: https://github.com/giampaolo/psutil
|
||||
Author: Giampaolo Rodola
|
||||
Author-email: g.rodola <at> gmail <dot> com
|
||||
License: BSD
|
||||
Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pypi.python.org/pypi/psutil#downloads
|
||||
:alt: Downloads this month
|
||||
|
||||
.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master
|
||||
:target: https://travis-ci.org/giampaolo/psutil
|
||||
:alt: Linux tests (Travis)
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true
|
||||
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
||||
:alt: Windows tests (Appveyor)
|
||||
|
||||
.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github
|
||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||
:alt: Test coverage (coverall.io)
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/psutil.svg
|
||||
:target: https://pypi.python.org/pypi/psutil/
|
||||
:alt: Latest version
|
||||
|
||||
.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/
|
||||
:alt: Github stars
|
||||
|
||||
.. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg
|
||||
:target: https://scrutinizer-ci.com/g/giampaolo/psutil/
|
||||
:alt: Code quality (scrutinizer-ci.com)
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
||||
:target: https://pypi.python.org/pypi/psutil/
|
||||
:alt: License
|
||||
|
||||
===========
|
||||
Quick links
|
||||
===========
|
||||
|
||||
- `Home page <https://github.com/giampaolo/psutil>`_
|
||||
- `Documentation <http://pythonhosted.org/psutil/>`_
|
||||
- `Installation <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
||||
- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
|
||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
|
||||
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
|
||||
|
||||
=======
|
||||
Summary
|
||||
=======
|
||||
|
||||
psutil (python system and process utilities) is a cross-platform library for
|
||||
retrieving information on **running processes** and **system utilization**
|
||||
(CPU, memory, disks, network) in Python. It is useful mainly for **system
|
||||
monitoring**, **profiling and limiting process resources** and **management of
|
||||
running processes**. It implements many functionalities offered by command line
|
||||
tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice,
|
||||
ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports
|
||||
**Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and
|
||||
**64-bit** architectures, with Python versions from **2.6 to 3.5** (users of
|
||||
Python 2.4 and 2.5 may use `2.1.3 <https://pypi.python.org/pypi?name=psutil&version=2.1.3&:action=files>`__ version).
|
||||
`PyPy <http://pypy.org/>`__ is also known to work.
|
||||
|
||||
====================
|
||||
Example applications
|
||||
====================
|
||||
|
||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png
|
||||
:target: http://psutil.googlecode.com/svn/wiki/images/top.png
|
||||
:alt: top
|
||||
|
||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png
|
||||
:target: http://psutil.googlecode.com/svn/wiki/images/nettop.png
|
||||
:alt: nettop
|
||||
|
||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png
|
||||
:target: http://psutil.googlecode.com/svn/wiki/images/iotop.png
|
||||
:alt: iotop
|
||||
|
||||
See also:
|
||||
|
||||
* https://github.com/nicolargo/glances
|
||||
* https://github.com/google/grr
|
||||
* https://github.com/Jahaja/psdash
|
||||
|
||||
==============
|
||||
Example usages
|
||||
==============
|
||||
|
||||
CPU
|
||||
===
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.cpu_times()
|
||||
scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1)
|
||||
...
|
||||
4.0
|
||||
5.9
|
||||
3.8
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1, percpu=True)
|
||||
...
|
||||
[4.0, 6.9, 3.7, 9.2]
|
||||
[7.0, 8.5, 2.4, 2.1]
|
||||
[1.2, 9.0, 9.9, 7.2]
|
||||
>>>
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_times_percent(interval=1, percpu=False)
|
||||
...
|
||||
scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
>>>
|
||||
>>> psutil.cpu_count()
|
||||
4
|
||||
>>> psutil.cpu_count(logical=False)
|
||||
2
|
||||
>>>
|
||||
|
||||
Memory
|
||||
======
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.virtual_memory()
|
||||
svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336)
|
||||
>>> psutil.swap_memory()
|
||||
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
||||
>>>
|
||||
|
||||
Disks
|
||||
=====
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.disk_partitions()
|
||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
||||
>>>
|
||||
>>> psutil.disk_usage('/')
|
||||
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
||||
>>>
|
||||
>>> psutil.disk_io_counters(perdisk=False)
|
||||
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568)
|
||||
>>>
|
||||
|
||||
Network
|
||||
=======
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.net_io_counters(pernic=True)
|
||||
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
||||
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
|
||||
>>>
|
||||
>>> psutil.net_connections()
|
||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
|
||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
|
||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
|
||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
|
||||
...]
|
||||
>>>
|
||||
>>> psutil.net_if_addrs()
|
||||
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'),
|
||||
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None),
|
||||
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')],
|
||||
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'),
|
||||
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None),
|
||||
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]}
|
||||
>>>
|
||||
>>> psutil.net_if_stats()
|
||||
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
||||
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
||||
|
||||
Other system info
|
||||
=================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.users()
|
||||
[user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0),
|
||||
user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)]
|
||||
>>>
|
||||
>>> psutil.boot_time()
|
||||
1365519115.0
|
||||
>>>
|
||||
|
||||
Process management
|
||||
==================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.pids()
|
||||
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224,
|
||||
268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355,
|
||||
2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245,
|
||||
4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358,
|
||||
4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235,
|
||||
5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
||||
>>>
|
||||
>>> p = psutil.Process(7055)
|
||||
>>> p.name()
|
||||
'python'
|
||||
>>> p.exe()
|
||||
'/usr/bin/python'
|
||||
>>> p.cwd()
|
||||
'/home/giampaolo'
|
||||
>>> p.cmdline()
|
||||
['/usr/bin/python', 'main.py']
|
||||
>>>
|
||||
>>> p.status()
|
||||
'running'
|
||||
>>> p.username()
|
||||
'giampaolo'
|
||||
>>> p.create_time()
|
||||
1267551141.5019531
|
||||
>>> p.terminal()
|
||||
'/dev/pts/0'
|
||||
>>>
|
||||
>>> p.uids()
|
||||
puids(real=1000, effective=1000, saved=1000)
|
||||
>>> p.gids()
|
||||
pgids(real=1000, effective=1000, saved=1000)
|
||||
>>>
|
||||
>>> p.cpu_times()
|
||||
pcputimes(user=1.02, system=0.31)
|
||||
>>> p.cpu_percent(interval=1.0)
|
||||
12.1
|
||||
>>> p.cpu_affinity()
|
||||
[0, 1, 2, 3]
|
||||
>>> p.cpu_affinity([0]) # set
|
||||
>>>
|
||||
>>> p.memory_percent()
|
||||
0.63423
|
||||
>>>
|
||||
>>> p.memory_info()
|
||||
pmem(rss=7471104, vms=68513792)
|
||||
>>> p.memory_info_ex()
|
||||
extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0)
|
||||
>>> p.memory_maps()
|
||||
[pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0),
|
||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0),
|
||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0),
|
||||
pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0),
|
||||
pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0),
|
||||
...]
|
||||
>>>
|
||||
>>> p.io_counters()
|
||||
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
|
||||
>>>
|
||||
>>> p.open_files()
|
||||
[popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
|
||||
>>>
|
||||
>>> p.connections()
|
||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
|
||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
|
||||
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
|
||||
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
|
||||
>>>
|
||||
>>> p.num_threads()
|
||||
4
|
||||
>>> p.num_fds()
|
||||
8
|
||||
>>> p.threads()
|
||||
[pthread(id=5234, user_time=22.5, system_time=9.2891),
|
||||
pthread(id=5235, user_time=0.0, system_time=0.0),
|
||||
pthread(id=5236, user_time=0.0, system_time=0.0),
|
||||
pthread(id=5237, user_time=0.0707, system_time=1.1)]
|
||||
>>>
|
||||
>>> p.num_ctx_switches()
|
||||
pctxsw(voluntary=78, involuntary=19)
|
||||
>>>
|
||||
>>> p.nice()
|
||||
0
|
||||
>>> p.nice(10) # set
|
||||
>>>
|
||||
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)
|
||||
>>> p.ionice()
|
||||
pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
|
||||
>>>
|
||||
>>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only)
|
||||
>>> p.rlimit(psutil.RLIMIT_NOFILE)
|
||||
(5, 5)
|
||||
>>>
|
||||
>>> p.suspend()
|
||||
>>> p.resume()
|
||||
>>>
|
||||
>>> p.terminate()
|
||||
>>> p.wait(timeout=3)
|
||||
0
|
||||
>>>
|
||||
>>> psutil.test()
|
||||
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
|
||||
root 1 0.0 0.0 24584 2240 Jun17 00:00 init
|
||||
root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd
|
||||
root 3 0.0 0.0 0 0 Jun17 00:05 ksoftirqd/0
|
||||
...
|
||||
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
|
||||
giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome
|
||||
root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1
|
||||
>>>
|
||||
|
||||
Further process APIs
|
||||
====================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> for p in psutil.process_iter():
|
||||
... print(p)
|
||||
...
|
||||
psutil.Process(pid=1, name='init')
|
||||
psutil.Process(pid=2, name='kthreadd')
|
||||
psutil.Process(pid=3, name='ksoftirqd/0')
|
||||
...
|
||||
>>>
|
||||
>>> def on_terminate(proc):
|
||||
... print("process {} terminated".format(proc))
|
||||
...
|
||||
>>> # waits for multiple processes to terminate
|
||||
>>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate)
|
||||
>>>
|
||||
|
||||
======
|
||||
Donate
|
||||
======
|
||||
|
||||
A lot of time and effort went into making psutil as it is right now.
|
||||
If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`_) some money.
|
||||
I only ask for a small donation, but of course I appreciate any amount.
|
||||
|
||||
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
||||
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||
:alt: Donate via PayPal
|
||||
|
||||
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <http://www.linkedin.com/in/grodola>`_.
|
||||
|
||||
============
|
||||
Mailing list
|
||||
============
|
||||
|
||||
http://groups.google.com/group/psutil/
|
||||
|
||||
========
|
||||
Timeline
|
||||
========
|
||||
|
||||
- 2015-07-15: `psutil-3.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.1.tar.gz>`_
|
||||
- 2015-07-15: `psutil-3.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.0.tar.gz>`_
|
||||
- 2015-06-18: `psutil-3.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.1.tar.gz>`_
|
||||
- 2015-06-13: `psutil-3.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.0.tar.gz>`_
|
||||
- 2015-02-02: `psutil-2.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.1.tar.gz>`_
|
||||
- 2015-01-06: `psutil-2.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.0.tar.gz>`_
|
||||
- 2014-09-26: `psutil-2.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.3.tar.gz>`_
|
||||
- 2014-09-21: `psutil-2.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.2.tar.gz>`_
|
||||
- 2014-04-30: `psutil-2.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.1.tar.gz>`_
|
||||
- 2014-04-08: `psutil-2.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.0.tar.gz>`_
|
||||
- 2014-03-10: `psutil-2.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.0.0.tar.gz>`_
|
||||
- 2013-11-25: `psutil-1.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.1.tar.gz>`_
|
||||
- 2013-11-20: `psutil-1.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.0.tar.gz>`_
|
||||
- 2013-11-07: `psutil-1.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.3.tar.gz>`_
|
||||
- 2013-10-22: `psutil-1.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.2.tar.gz>`_
|
||||
- 2013-10-08: `psutil-1.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.1.tar.gz>`_
|
||||
- 2013-09-28: `psutil-1.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.0.tar.gz>`_
|
||||
- 2013-07-12: `psutil-1.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.1.tar.gz>`_
|
||||
- 2013-07-10: `psutil-1.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.0.tar.gz>`_
|
||||
- 2013-05-03: `psutil-0.7.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.1.tar.gz>`_
|
||||
- 2013-04-12: `psutil-0.7.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.0.tar.gz>`_
|
||||
- 2012-08-16: `psutil-0.6.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.1.tar.gz>`_
|
||||
- 2012-08-13: `psutil-0.6.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.0.tar.gz>`_
|
||||
- 2012-06-29: `psutil-0.5.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.1.tar.gz>`_
|
||||
- 2012-06-27: `psutil-0.5.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.0.tar.gz>`_
|
||||
- 2011-12-14: `psutil-0.4.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.1.tar.gz>`_
|
||||
- 2011-10-29: `psutil-0.4.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.0.tar.gz>`_
|
||||
- 2011-07-08: `psutil-0.3.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.3.0.tar.gz>`_
|
||||
- 2011-03-20: `psutil-0.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.1.tar.gz>`_
|
||||
- 2010-11-13: `psutil-0.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.0.tar.gz>`_
|
||||
- 2010-03-02: `psutil-0.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.3.tar.gz>`_
|
||||
- 2009-05-06: `psutil-0.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.2.tar.gz>`_
|
||||
- 2009-03-06: `psutil-0.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.1.tar.gz>`_
|
||||
- 2009-01-27: `psutil-0.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.0.tar.gz>`_
|
||||
|
||||
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit
|
||||
Platform: Platform Independent
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Environment :: Win32 (MS Windows)
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: MacOS :: MacOS X
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000
|
||||
Classifier: Operating System :: Microsoft
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
|
||||
Classifier: Operating System :: POSIX :: Linux
|
||||
Classifier: Operating System :: POSIX :: SunOS/Solaris
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Programming Language :: C
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.0
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Software Development :: Libraries
|
||||
Classifier: Topic :: System :: Benchmark
|
||||
Classifier: Topic :: System :: Hardware
|
||||
Classifier: Topic :: System :: Monitoring
|
||||
Classifier: Topic :: System :: Networking :: Monitoring
|
||||
Classifier: Topic :: System :: Networking
|
||||
Classifier: Topic :: System :: Systems Administration
|
||||
Classifier: Topic :: Utilities
|
||||
386
python/psutil/README.rst
Normal file
386
python/psutil/README.rst
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
.. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pypi.python.org/pypi/psutil#downloads
|
||||
:alt: Downloads this month
|
||||
|
||||
.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master
|
||||
:target: https://travis-ci.org/giampaolo/psutil
|
||||
:alt: Linux tests (Travis)
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true
|
||||
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
||||
:alt: Windows tests (Appveyor)
|
||||
|
||||
.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github
|
||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||
:alt: Test coverage (coverall.io)
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/psutil.svg
|
||||
:target: https://pypi.python.org/pypi/psutil/
|
||||
:alt: Latest version
|
||||
|
||||
.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/
|
||||
:alt: Github stars
|
||||
|
||||
.. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg
|
||||
:target: https://scrutinizer-ci.com/g/giampaolo/psutil/
|
||||
:alt: Code quality (scrutinizer-ci.com)
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
||||
:target: https://pypi.python.org/pypi/psutil/
|
||||
:alt: License
|
||||
|
||||
===========
|
||||
Quick links
|
||||
===========
|
||||
|
||||
- `Home page <https://github.com/giampaolo/psutil>`_
|
||||
- `Documentation <http://pythonhosted.org/psutil/>`_
|
||||
- `Installation <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
||||
- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
|
||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
|
||||
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
|
||||
|
||||
=======
|
||||
Summary
|
||||
=======
|
||||
|
||||
psutil (python system and process utilities) is a cross-platform library for
|
||||
retrieving information on **running processes** and **system utilization**
|
||||
(CPU, memory, disks, network) in Python. It is useful mainly for **system
|
||||
monitoring**, **profiling and limiting process resources** and **management of
|
||||
running processes**. It implements many functionalities offered by command line
|
||||
tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice,
|
||||
ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports
|
||||
**Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and
|
||||
**64-bit** architectures, with Python versions from **2.6 to 3.5** (users of
|
||||
Python 2.4 and 2.5 may use `2.1.3 <https://pypi.python.org/pypi?name=psutil&version=2.1.3&:action=files>`__ version).
|
||||
`PyPy <http://pypy.org/>`__ is also known to work.
|
||||
|
||||
====================
|
||||
Example applications
|
||||
====================
|
||||
|
||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png
|
||||
:target: http://psutil.googlecode.com/svn/wiki/images/top.png
|
||||
:alt: top
|
||||
|
||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png
|
||||
:target: http://psutil.googlecode.com/svn/wiki/images/nettop.png
|
||||
:alt: nettop
|
||||
|
||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png
|
||||
:target: http://psutil.googlecode.com/svn/wiki/images/iotop.png
|
||||
:alt: iotop
|
||||
|
||||
See also:
|
||||
|
||||
* https://github.com/nicolargo/glances
|
||||
* https://github.com/google/grr
|
||||
* https://github.com/Jahaja/psdash
|
||||
|
||||
==============
|
||||
Example usages
|
||||
==============
|
||||
|
||||
CPU
|
||||
===
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.cpu_times()
|
||||
scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1)
|
||||
...
|
||||
4.0
|
||||
5.9
|
||||
3.8
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1, percpu=True)
|
||||
...
|
||||
[4.0, 6.9, 3.7, 9.2]
|
||||
[7.0, 8.5, 2.4, 2.1]
|
||||
[1.2, 9.0, 9.9, 7.2]
|
||||
>>>
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_times_percent(interval=1, percpu=False)
|
||||
...
|
||||
scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
>>>
|
||||
>>> psutil.cpu_count()
|
||||
4
|
||||
>>> psutil.cpu_count(logical=False)
|
||||
2
|
||||
>>>
|
||||
|
||||
Memory
|
||||
======
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.virtual_memory()
|
||||
svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336)
|
||||
>>> psutil.swap_memory()
|
||||
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
||||
>>>
|
||||
|
||||
Disks
|
||||
=====
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.disk_partitions()
|
||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
||||
>>>
|
||||
>>> psutil.disk_usage('/')
|
||||
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
||||
>>>
|
||||
>>> psutil.disk_io_counters(perdisk=False)
|
||||
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568)
|
||||
>>>
|
||||
|
||||
Network
|
||||
=======
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.net_io_counters(pernic=True)
|
||||
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
||||
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
|
||||
>>>
|
||||
>>> psutil.net_connections()
|
||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
|
||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
|
||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
|
||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
|
||||
...]
|
||||
>>>
|
||||
>>> psutil.net_if_addrs()
|
||||
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'),
|
||||
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None),
|
||||
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')],
|
||||
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'),
|
||||
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None),
|
||||
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]}
|
||||
>>>
|
||||
>>> psutil.net_if_stats()
|
||||
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
||||
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
||||
|
||||
Other system info
|
||||
=================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.users()
|
||||
[user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0),
|
||||
user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)]
|
||||
>>>
|
||||
>>> psutil.boot_time()
|
||||
1365519115.0
|
||||
>>>
|
||||
|
||||
Process management
|
||||
==================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.pids()
|
||||
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224,
|
||||
268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355,
|
||||
2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245,
|
||||
4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358,
|
||||
4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235,
|
||||
5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
||||
>>>
|
||||
>>> p = psutil.Process(7055)
|
||||
>>> p.name()
|
||||
'python'
|
||||
>>> p.exe()
|
||||
'/usr/bin/python'
|
||||
>>> p.cwd()
|
||||
'/home/giampaolo'
|
||||
>>> p.cmdline()
|
||||
['/usr/bin/python', 'main.py']
|
||||
>>>
|
||||
>>> p.status()
|
||||
'running'
|
||||
>>> p.username()
|
||||
'giampaolo'
|
||||
>>> p.create_time()
|
||||
1267551141.5019531
|
||||
>>> p.terminal()
|
||||
'/dev/pts/0'
|
||||
>>>
|
||||
>>> p.uids()
|
||||
puids(real=1000, effective=1000, saved=1000)
|
||||
>>> p.gids()
|
||||
pgids(real=1000, effective=1000, saved=1000)
|
||||
>>>
|
||||
>>> p.cpu_times()
|
||||
pcputimes(user=1.02, system=0.31)
|
||||
>>> p.cpu_percent(interval=1.0)
|
||||
12.1
|
||||
>>> p.cpu_affinity()
|
||||
[0, 1, 2, 3]
|
||||
>>> p.cpu_affinity([0]) # set
|
||||
>>>
|
||||
>>> p.memory_percent()
|
||||
0.63423
|
||||
>>>
|
||||
>>> p.memory_info()
|
||||
pmem(rss=7471104, vms=68513792)
|
||||
>>> p.memory_info_ex()
|
||||
extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0)
|
||||
>>> p.memory_maps()
|
||||
[pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0),
|
||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0),
|
||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0),
|
||||
pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0),
|
||||
pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0),
|
||||
...]
|
||||
>>>
|
||||
>>> p.io_counters()
|
||||
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
|
||||
>>>
|
||||
>>> p.open_files()
|
||||
[popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
|
||||
>>>
|
||||
>>> p.connections()
|
||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
|
||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
|
||||
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
|
||||
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
|
||||
>>>
|
||||
>>> p.num_threads()
|
||||
4
|
||||
>>> p.num_fds()
|
||||
8
|
||||
>>> p.threads()
|
||||
[pthread(id=5234, user_time=22.5, system_time=9.2891),
|
||||
pthread(id=5235, user_time=0.0, system_time=0.0),
|
||||
pthread(id=5236, user_time=0.0, system_time=0.0),
|
||||
pthread(id=5237, user_time=0.0707, system_time=1.1)]
|
||||
>>>
|
||||
>>> p.num_ctx_switches()
|
||||
pctxsw(voluntary=78, involuntary=19)
|
||||
>>>
|
||||
>>> p.nice()
|
||||
0
|
||||
>>> p.nice(10) # set
|
||||
>>>
|
||||
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)
|
||||
>>> p.ionice()
|
||||
pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
|
||||
>>>
|
||||
>>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only)
|
||||
>>> p.rlimit(psutil.RLIMIT_NOFILE)
|
||||
(5, 5)
|
||||
>>>
|
||||
>>> p.suspend()
|
||||
>>> p.resume()
|
||||
>>>
|
||||
>>> p.terminate()
|
||||
>>> p.wait(timeout=3)
|
||||
0
|
||||
>>>
|
||||
>>> psutil.test()
|
||||
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
|
||||
root 1 0.0 0.0 24584 2240 Jun17 00:00 init
|
||||
root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd
|
||||
root 3 0.0 0.0 0 0 Jun17 00:05 ksoftirqd/0
|
||||
...
|
||||
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
|
||||
giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome
|
||||
root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1
|
||||
>>>
|
||||
|
||||
Further process APIs
|
||||
====================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> for p in psutil.process_iter():
|
||||
... print(p)
|
||||
...
|
||||
psutil.Process(pid=1, name='init')
|
||||
psutil.Process(pid=2, name='kthreadd')
|
||||
psutil.Process(pid=3, name='ksoftirqd/0')
|
||||
...
|
||||
>>>
|
||||
>>> def on_terminate(proc):
|
||||
... print("process {} terminated".format(proc))
|
||||
...
|
||||
>>> # waits for multiple processes to terminate
|
||||
>>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate)
|
||||
>>>
|
||||
|
||||
======
|
||||
Donate
|
||||
======
|
||||
|
||||
A lot of time and effort went into making psutil as it is right now.
|
||||
If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`_) some money.
|
||||
I only ask for a small donation, but of course I appreciate any amount.
|
||||
|
||||
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
||||
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||
:alt: Donate via PayPal
|
||||
|
||||
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <http://www.linkedin.com/in/grodola>`_.
|
||||
|
||||
============
|
||||
Mailing list
|
||||
============
|
||||
|
||||
http://groups.google.com/group/psutil/
|
||||
|
||||
========
|
||||
Timeline
|
||||
========
|
||||
|
||||
- 2015-07-15: `psutil-3.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.1.tar.gz>`_
|
||||
- 2015-07-15: `psutil-3.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.0.tar.gz>`_
|
||||
- 2015-06-18: `psutil-3.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.1.tar.gz>`_
|
||||
- 2015-06-13: `psutil-3.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.0.tar.gz>`_
|
||||
- 2015-02-02: `psutil-2.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.1.tar.gz>`_
|
||||
- 2015-01-06: `psutil-2.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.0.tar.gz>`_
|
||||
- 2014-09-26: `psutil-2.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.3.tar.gz>`_
|
||||
- 2014-09-21: `psutil-2.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.2.tar.gz>`_
|
||||
- 2014-04-30: `psutil-2.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.1.tar.gz>`_
|
||||
- 2014-04-08: `psutil-2.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.0.tar.gz>`_
|
||||
- 2014-03-10: `psutil-2.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.0.0.tar.gz>`_
|
||||
- 2013-11-25: `psutil-1.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.1.tar.gz>`_
|
||||
- 2013-11-20: `psutil-1.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.0.tar.gz>`_
|
||||
- 2013-11-07: `psutil-1.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.3.tar.gz>`_
|
||||
- 2013-10-22: `psutil-1.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.2.tar.gz>`_
|
||||
- 2013-10-08: `psutil-1.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.1.tar.gz>`_
|
||||
- 2013-09-28: `psutil-1.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.0.tar.gz>`_
|
||||
- 2013-07-12: `psutil-1.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.1.tar.gz>`_
|
||||
- 2013-07-10: `psutil-1.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.0.tar.gz>`_
|
||||
- 2013-05-03: `psutil-0.7.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.1.tar.gz>`_
|
||||
- 2013-04-12: `psutil-0.7.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.0.tar.gz>`_
|
||||
- 2012-08-16: `psutil-0.6.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.1.tar.gz>`_
|
||||
- 2012-08-13: `psutil-0.6.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.0.tar.gz>`_
|
||||
- 2012-06-29: `psutil-0.5.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.1.tar.gz>`_
|
||||
- 2012-06-27: `psutil-0.5.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.0.tar.gz>`_
|
||||
- 2011-12-14: `psutil-0.4.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.1.tar.gz>`_
|
||||
- 2011-10-29: `psutil-0.4.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.0.tar.gz>`_
|
||||
- 2011-07-08: `psutil-0.3.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.3.0.tar.gz>`_
|
||||
- 2011-03-20: `psutil-0.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.1.tar.gz>`_
|
||||
- 2010-11-13: `psutil-0.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.0.tar.gz>`_
|
||||
- 2010-03-02: `psutil-0.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.3.tar.gz>`_
|
||||
- 2009-05-06: `psutil-0.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.2.tar.gz>`_
|
||||
- 2009-03-06: `psutil-0.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.1.tar.gz>`_
|
||||
- 2009-01-27: `psutil-0.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.0.tar.gz>`_
|
||||
167
python/psutil/TODO
Normal file
167
python/psutil/TODO
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
TODO
|
||||
====
|
||||
|
||||
A collection of ideas and notes about stuff to implement in future versions.
|
||||
"#NNN" occurrences refer to bug tracker issues at:
|
||||
https://github.com/giampaolo/psutil/issues
|
||||
|
||||
|
||||
HIGHER PRIORITY
|
||||
===============
|
||||
|
||||
* OpenBSD support.
|
||||
|
||||
* #371: CPU temperature (apparently OSX and Linux only; on Linux it requires
|
||||
lm-sensors lib).
|
||||
|
||||
* #269: expose network ifaces RX/TW queues. This should probably go into
|
||||
net_if_stats(). Figure out on what platforms this is supported:
|
||||
Linux: yes
|
||||
Others: ?
|
||||
|
||||
* Process.threads(): thread names; patch for OSX available at:
|
||||
https://code.google.com/p/plcrashreporter/issues/detail?id=65
|
||||
|
||||
* Asynchronous psutil.Popen (see http://bugs.python.org/issue1191964)
|
||||
|
||||
* (Windows) fall back on using WMIC for Process methods returning AccessDenied
|
||||
|
||||
* #613: thread names.
|
||||
|
||||
* #604: emulate os.getloadavg() on Windows
|
||||
|
||||
* #269: NIC rx/tx queue.
|
||||
|
||||
|
||||
LOWER PRIORITY
|
||||
==============
|
||||
|
||||
* #355: Android support.
|
||||
|
||||
* #276: GNU/Hurd support.
|
||||
|
||||
* #429: NetBSD support.
|
||||
|
||||
* DragonFlyBSD support?
|
||||
|
||||
* AIX support?
|
||||
|
||||
* examples/taskmgr-gui.py (using tk).
|
||||
|
||||
* system-wide number of open file descriptors:
|
||||
* https://jira.hyperic.com/browse/SIGAR-30
|
||||
* http://www.netadmintools.com/part295.html
|
||||
|
||||
* Number of system threads.
|
||||
* Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684824(v=vs.85).aspx
|
||||
|
||||
* #357: what CPU a process is on.
|
||||
|
||||
* Doc / wiki which compares similarities between UNIX cli tools and psutil.
|
||||
Example:
|
||||
df -a -> psutil.disk_partitions
|
||||
lsof -> psutil.Process.open_files() and psutil.Process.open_connections()
|
||||
killall-> (actual script)
|
||||
tty -> psutil.Process.terminal()
|
||||
who -> psutil.users()
|
||||
|
||||
|
||||
DEBATABLE
|
||||
=========
|
||||
|
||||
* psutil.proc_tree() something which obtains a {pid:ppid, ...} dict for
|
||||
all running processes in one shot. This can be factored out from
|
||||
Process.children() and exposed as a first class function.
|
||||
PROS: on Windows we can take advantage of _psutil_windows.ppid_map()
|
||||
which is faster than iterating over all pids and calling ppid().
|
||||
CONS: examples/pstree.py shows this can be easily done in the user code
|
||||
so maybe it's not worth the addition.
|
||||
|
||||
* advanced cmdline interface exposing the whole API and providing different
|
||||
kind of outputs (e.g. pprinted, colorized, json).
|
||||
|
||||
* [Linux]: process cgroups (http://en.wikipedia.org/wiki/Cgroups). They look
|
||||
similar to prlimit() in terms of functionality but uglier (they should allow
|
||||
limiting per-process network IO resources though, which is great). Needs
|
||||
further reading.
|
||||
|
||||
* Should we expose OS constants (psutil.WINDOWS, psutil.OSX etc.)?
|
||||
|
||||
* Python 3.3. exposed different sched.h functions:
|
||||
http://docs.python.org/dev/whatsnew/3.3.html#os
|
||||
http://bugs.python.org/issue12655
|
||||
http://docs.python.org/dev/library/os.html#interface-to-the-scheduler
|
||||
It might be worth to take a look and figure out whether we can include some
|
||||
of those in psutil.
|
||||
Also, we can probably reimplement wait_pid() on POSIX which is currently
|
||||
implemented as a busy-loop.
|
||||
|
||||
* Certain systems provide CPU times about process children. On those systems
|
||||
Process.cpu_times() might return a (user, system, user_children,
|
||||
system_children) ntuple.
|
||||
* Linux: /proc/{PID}/stat
|
||||
* Solaris: pr_cutime and pr_cstime
|
||||
* FreeBSD: none
|
||||
* OSX: none
|
||||
* Windows: none
|
||||
|
||||
* ...also, os.times() provides 'elapsed' times as well.
|
||||
|
||||
* ...also Linux provides guest_time and cguest_time.
|
||||
|
||||
* Enrich exception classes hierarchy on Python >= 3.3 / post PEP-3151 so that:
|
||||
- NoSuchProcess inherits from ProcessLookupError
|
||||
- AccessDenied inherits from PermissionError
|
||||
- TimeoutExpired inherits from TimeoutError (debatable)
|
||||
See: http://docs.python.org/3/library/exceptions.html#os-exceptions
|
||||
|
||||
* Process.threads() might grow an extra "id" parameter so that it can be
|
||||
used as such:
|
||||
|
||||
>>> p = psutil.Process(os.getpid())
|
||||
>>> p.threads(id=psutil.current_thread_id())
|
||||
thread(id=2539, user_time=0.03, system_time=0.02)
|
||||
>>>
|
||||
|
||||
Note: this leads to questions such as "should we have a custom NoSuchThread
|
||||
exception? Also see issue #418.
|
||||
|
||||
Note #2: this would work with os.getpid() only.
|
||||
psutil.current_thread_id() might be desirable as per issue #418 though.
|
||||
|
||||
* should psutil.TimeoutExpired exception have a 'msg' kwarg similar to
|
||||
NoSuchProcess and AccessDenied? Not that we need it, but currently we
|
||||
cannot raise a TimeoutExpired exception with a specific error string.
|
||||
|
||||
* process_iter() might grow an "attrs" parameter similar to Process.as_dict()
|
||||
invoke the necessary methods and include the results into a "cache"
|
||||
attribute attached to the returned Process instances so that one can avoid
|
||||
catching NSP and AccessDenied:
|
||||
for p in process_iter(attrs=['cpu_percent']):
|
||||
print(p.cache['cpu_percent'])
|
||||
This also leads questions as whether we should introduce a sorting order.
|
||||
|
||||
* round Process.memory_percent() result?
|
||||
|
||||
* #550: number of threads per core.
|
||||
|
||||
* Have psutil.Process().cpu_affinity([]) be an alias for "all CPUs"?
|
||||
|
||||
|
||||
COMPATIBILITY BREAKAGE
|
||||
======================
|
||||
|
||||
Removals (will likely happen in 2.2):
|
||||
|
||||
* (S) psutil.Process.nice (deprecated in 0.5.0)
|
||||
* (S) get_process_list (deprecated in 0.5.0)
|
||||
* (S) psutil.*mem* functions (deprecated in 0.3.0 and 0.6.0)
|
||||
* (M) psutil.network_io_counters (deprecated in 1.0.0)
|
||||
* (M) local_address and remote_address Process.connection() namedtuple fields
|
||||
(deprecated in 1.0.0)
|
||||
|
||||
|
||||
REJECTED IDEAS
|
||||
==============
|
||||
|
||||
STUB
|
||||
177
python/psutil/docs/Makefile
Normal file
177
python/psutil/docs/Makefile
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/psutil.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/psutil.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/psutil"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/psutil"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
15
python/psutil/docs/README
Normal file
15
python/psutil/docs/README
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
About
|
||||
=====
|
||||
|
||||
This directory contains the reStructuredText (reST) sources to the psutil
|
||||
documentation. You don't need to build them yourself, prebuilt versions are
|
||||
available at https://pythonhosted.org/psutil/.
|
||||
In case you want, you need to install sphinx first:
|
||||
|
||||
$ pip install sphinx
|
||||
|
||||
Then run:
|
||||
|
||||
$ make html
|
||||
|
||||
You'll then have an HTML version of the doc at _build/html/index.html.
|
||||
57
python/psutil/docs/_static/copybutton.js
vendored
Normal file
57
python/psutil/docs/_static/copybutton.js
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
$(document).ready(function() {
|
||||
/* Add a [>>>] button on the top-right corner of code samples to hide
|
||||
* the >>> and ... prompts and the output and thus make the code
|
||||
* copyable. */
|
||||
var div = $('.highlight-python .highlight,' +
|
||||
'.highlight-python3 .highlight')
|
||||
var pre = div.find('pre');
|
||||
|
||||
// get the styles from the current theme
|
||||
pre.parent().parent().css('position', 'relative');
|
||||
var hide_text = 'Hide the prompts and output';
|
||||
var show_text = 'Show the prompts and output';
|
||||
var border_width = pre.css('border-top-width');
|
||||
var border_style = pre.css('border-top-style');
|
||||
var border_color = pre.css('border-top-color');
|
||||
var button_styles = {
|
||||
'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0',
|
||||
'border-color': border_color, 'border-style': border_style,
|
||||
'border-width': border_width, 'color': border_color, 'text-size': '75%',
|
||||
'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em',
|
||||
'border-radius': '0 3px 0 0'
|
||||
}
|
||||
|
||||
// create and add the button to all the code blocks that contain >>>
|
||||
div.each(function(index) {
|
||||
var jthis = $(this);
|
||||
if (jthis.find('.gp').length > 0) {
|
||||
var button = $('<span class="copybutton">>>></span>');
|
||||
button.css(button_styles)
|
||||
button.attr('title', hide_text);
|
||||
jthis.prepend(button);
|
||||
}
|
||||
// tracebacks (.gt) contain bare text elements that need to be
|
||||
// wrapped in a span to work with .nextUntil() (see later)
|
||||
jthis.find('pre:has(.gt)').contents().filter(function() {
|
||||
return ((this.nodeType == 3) && (this.data.trim().length > 0));
|
||||
}).wrap('<span>');
|
||||
});
|
||||
|
||||
// define the behavior of the button when it's clicked
|
||||
$('.copybutton').toggle(
|
||||
function() {
|
||||
var button = $(this);
|
||||
button.parent().find('.go, .gp, .gt').hide();
|
||||
button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden');
|
||||
button.css('text-decoration', 'line-through');
|
||||
button.attr('title', show_text);
|
||||
},
|
||||
function() {
|
||||
var button = $(this);
|
||||
button.parent().find('.go, .gp, .gt').show();
|
||||
button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible');
|
||||
button.css('text-decoration', 'none');
|
||||
button.attr('title', hide_text);
|
||||
});
|
||||
});
|
||||
|
||||
BIN
python/psutil/docs/_static/favicon.ico
vendored
Normal file
BIN
python/psutil/docs/_static/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
python/psutil/docs/_static/logo.png
vendored
Normal file
BIN
python/psutil/docs/_static/logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
161
python/psutil/docs/_static/sidebar.js
vendored
Normal file
161
python/psutil/docs/_static/sidebar.js
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* sidebar.js
|
||||
* ~~~~~~~~~~
|
||||
*
|
||||
* This script makes the Sphinx sidebar collapsible.
|
||||
*
|
||||
* .sphinxsidebar contains .sphinxsidebarwrapper. This script adds in
|
||||
* .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to
|
||||
* collapse and expand the sidebar.
|
||||
*
|
||||
* When the sidebar is collapsed the .sphinxsidebarwrapper is hidden and the
|
||||
* width of the sidebar and the margin-left of the document are decreased.
|
||||
* When the sidebar is expanded the opposite happens. This script saves a
|
||||
* per-browser/per-session cookie used to remember the position of the sidebar
|
||||
* among the pages. Once the browser is closed the cookie is deleted and the
|
||||
* position reset to the default (expanded).
|
||||
*
|
||||
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
// global elements used by the functions.
|
||||
// the 'sidebarbutton' element is defined as global after its
|
||||
// creation, in the add_sidebar_button function
|
||||
var bodywrapper = $('.bodywrapper');
|
||||
var sidebar = $('.sphinxsidebar');
|
||||
var sidebarwrapper = $('.sphinxsidebarwrapper');
|
||||
|
||||
// original margin-left of the bodywrapper and width of the sidebar
|
||||
// with the sidebar expanded
|
||||
var bw_margin_expanded = bodywrapper.css('margin-left');
|
||||
var ssb_width_expanded = sidebar.width();
|
||||
|
||||
// margin-left of the bodywrapper and width of the sidebar
|
||||
// with the sidebar collapsed
|
||||
var bw_margin_collapsed = '.8em';
|
||||
var ssb_width_collapsed = '.8em';
|
||||
|
||||
// colors used by the current theme
|
||||
var dark_color = '#AAAAAA';
|
||||
var light_color = '#CCCCCC';
|
||||
|
||||
function sidebar_is_collapsed() {
|
||||
return sidebarwrapper.is(':not(:visible)');
|
||||
}
|
||||
|
||||
function toggle_sidebar() {
|
||||
if (sidebar_is_collapsed())
|
||||
expand_sidebar();
|
||||
else
|
||||
collapse_sidebar();
|
||||
}
|
||||
|
||||
function collapse_sidebar() {
|
||||
sidebarwrapper.hide();
|
||||
sidebar.css('width', ssb_width_collapsed);
|
||||
bodywrapper.css('margin-left', bw_margin_collapsed);
|
||||
sidebarbutton.css({
|
||||
'margin-left': '0',
|
||||
//'height': bodywrapper.height(),
|
||||
'height': sidebar.height(),
|
||||
'border-radius': '5px'
|
||||
});
|
||||
sidebarbutton.find('span').text('»');
|
||||
sidebarbutton.attr('title', _('Expand sidebar'));
|
||||
document.cookie = 'sidebar=collapsed';
|
||||
}
|
||||
|
||||
function expand_sidebar() {
|
||||
bodywrapper.css('margin-left', bw_margin_expanded);
|
||||
sidebar.css('width', ssb_width_expanded);
|
||||
sidebarwrapper.show();
|
||||
sidebarbutton.css({
|
||||
'margin-left': ssb_width_expanded-12,
|
||||
//'height': bodywrapper.height(),
|
||||
'height': sidebar.height(),
|
||||
'border-radius': '0 5px 5px 0'
|
||||
});
|
||||
sidebarbutton.find('span').text('«');
|
||||
sidebarbutton.attr('title', _('Collapse sidebar'));
|
||||
//sidebarwrapper.css({'padding-top':
|
||||
// Math.max(window.pageYOffset - sidebarwrapper.offset().top, 10)});
|
||||
document.cookie = 'sidebar=expanded';
|
||||
}
|
||||
|
||||
function add_sidebar_button() {
|
||||
sidebarwrapper.css({
|
||||
'float': 'left',
|
||||
'margin-right': '0',
|
||||
'width': ssb_width_expanded - 28
|
||||
});
|
||||
// create the button
|
||||
sidebar.append(
|
||||
'<div id="sidebarbutton"><span>«</span></div>'
|
||||
);
|
||||
var sidebarbutton = $('#sidebarbutton');
|
||||
// find the height of the viewport to center the '<<' in the page
|
||||
var viewport_height;
|
||||
if (window.innerHeight)
|
||||
viewport_height = window.innerHeight;
|
||||
else
|
||||
viewport_height = $(window).height();
|
||||
var sidebar_offset = sidebar.offset().top;
|
||||
|
||||
var sidebar_height = sidebar.height();
|
||||
//var sidebar_height = Math.max(bodywrapper.height(), sidebar.height());
|
||||
sidebarbutton.find('span').css({
|
||||
'display': 'block',
|
||||
'margin-top': sidebar_height/2 - 10
|
||||
//'margin-top': (viewport_height - sidebar.position().top - 20) / 2
|
||||
//'position': 'fixed',
|
||||
//'top': Math.min(viewport_height/2, sidebar_height/2 + sidebar_offset) - 10
|
||||
});
|
||||
|
||||
sidebarbutton.click(toggle_sidebar);
|
||||
sidebarbutton.attr('title', _('Collapse sidebar'));
|
||||
sidebarbutton.css({
|
||||
'border-radius': '0 5px 5px 0',
|
||||
'color': '#444444',
|
||||
'background-color': '#CCCCCC',
|
||||
'font-size': '1.2em',
|
||||
'cursor': 'pointer',
|
||||
'height': sidebar_height,
|
||||
'padding-top': '1px',
|
||||
'padding-left': '1px',
|
||||
'margin-left': ssb_width_expanded - 12
|
||||
});
|
||||
|
||||
sidebarbutton.hover(
|
||||
function () {
|
||||
$(this).css('background-color', dark_color);
|
||||
},
|
||||
function () {
|
||||
$(this).css('background-color', light_color);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function set_position_from_cookie() {
|
||||
if (!document.cookie)
|
||||
return;
|
||||
var items = document.cookie.split(';');
|
||||
for(var k=0; k<items.length; k++) {
|
||||
var key_val = items[k].split('=');
|
||||
var key = key_val[0];
|
||||
if (key == 'sidebar') {
|
||||
var value = key_val[1];
|
||||
if ((value == 'collapsed') && (!sidebar_is_collapsed()))
|
||||
collapse_sidebar();
|
||||
else if ((value == 'expanded') && (sidebar_is_collapsed()))
|
||||
expand_sidebar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_sidebar_button();
|
||||
var sidebarbutton = $('#sidebarbutton');
|
||||
set_position_from_cookie();
|
||||
});
|
||||
12
python/psutil/docs/_template/globaltoc.html
vendored
Normal file
12
python/psutil/docs/_template/globaltoc.html
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{#
|
||||
basic/globaltoc.html
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sphinx sidebar template: global table of contents.
|
||||
|
||||
:copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
<h3>{{ _('Manual') }}</h3>
|
||||
{{ toctree() }}
|
||||
<a href="{{ pathto(master_doc) }}">Back to Welcome</a>
|
||||
4
python/psutil/docs/_template/indexcontent.html
vendored
Normal file
4
python/psutil/docs/_template/indexcontent.html
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{% extends "defindex.html" %}
|
||||
{% block tables %}
|
||||
|
||||
{% endblock %}
|
||||
8
python/psutil/docs/_template/indexsidebar.html
vendored
Normal file
8
python/psutil/docs/_template/indexsidebar.html
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<h3>Useful links</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/giampaolo/psutil">Github project</a></li>
|
||||
<li><a href="http://grodola.blogspot.com/search/label/psutil">Blog</a></li>
|
||||
<li><a href="https://pypi.python.org/pypi?:action=display&name=psutil#downloads">Download</a></li>
|
||||
<li><a href="https://github.com/giampaolo/psutil/issues">Issues</a></li>
|
||||
<li><a href="http://groups.google.com/group/psutil/topics">Forum</a></li>
|
||||
</ul>
|
||||
66
python/psutil/docs/_template/page.html
vendored
Normal file
66
python/psutil/docs/_template/page.html
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{% extends "!page.html" %}
|
||||
{% block extrahead %}
|
||||
{{ super() }}
|
||||
{% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script>{% endif %}
|
||||
<script type="text/javascript">
|
||||
|
||||
// Store editor pop-up help state in localStorage
|
||||
// so it does not re-pop-up itself between page loads.
|
||||
// Do not even to pretend to support IE gracefully.
|
||||
(function($) {
|
||||
|
||||
$(document).ready(function() {
|
||||
var box = $("#editor-trap");
|
||||
var klass = "toggled";
|
||||
var storageKey = "toggled";
|
||||
|
||||
function toggle() {
|
||||
box.toggleClass(klass);
|
||||
// Store the toggle status in local storage as "has value string" or null
|
||||
window.localStorage.setItem(storageKey, box.hasClass(klass) ? "toggled" : "not-toggled");
|
||||
}
|
||||
|
||||
box.click(toggle);
|
||||
|
||||
// Check the persistent state of the editor pop-up
|
||||
// Note that localStorage does not necessarily support boolean values (ugh!)
|
||||
// http://stackoverflow.com/questions/3263161/cannot-set-boolean-values-in-localstorage
|
||||
var v = window.localStorage.getItem(storageKey);
|
||||
if(v == "toggled" || !v) {
|
||||
box.addClass(klass);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-2097050-4']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block rootrellink %}
|
||||
<li><a href="https://github.com/giampaolo/psutil/"><img src="{{ pathto('_static/logo.png', 1) }}" style="height: 30px; vertical-align: middle; padding-right: 1em;" /> Project Homepage</a>{{ reldelim1 }}</li>
|
||||
<li><a href="{{ pathto('index') }}">{{ shorttitle }}</a>{{ reldelim1 }}</li>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block footer %}
|
||||
<div class="footer">
|
||||
© Copyright {{ copyright|e }}.
|
||||
<br />
|
||||
Last updated on {{ last_updated|e }}.
|
||||
<br />
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{ sphinx_version|e }}.
|
||||
</div>
|
||||
{% endblock %}
|
||||
187
python/psutil/docs/_themes/pydoctheme/static/pydoctheme.css
vendored
Normal file
187
python/psutil/docs/_themes/pydoctheme/static/pydoctheme.css
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
@import url("default.css");
|
||||
|
||||
body {
|
||||
background-color: white;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
div.related {
|
||||
margin-bottom: 1.2em;
|
||||
padding: 0.5em 0;
|
||||
border-top: 1px solid #ccc;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
div.related a:hover {
|
||||
color: #0095C4;
|
||||
}
|
||||
|
||||
div.related:first-child {
|
||||
border-top: 0;
|
||||
padding-top: 0;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
background-color: #eeeeee;
|
||||
border-radius: 5px;
|
||||
line-height: 130%;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3, div.sphinxsidebar h4 {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper > h3:first-child {
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper > ul > li > ul > li {
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar a:hover {
|
||||
color: #0095C4;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
font-family: 'Lucida Grande','Lucida Sans','DejaVu Sans',Arial,sans-serif;
|
||||
border: 1px solid #999999;
|
||||
font-size: smaller;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input[type=text] {
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
div.body {
|
||||
padding: 0 0 0 1.2em;
|
||||
}
|
||||
|
||||
div.body p {
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0.3em 0;
|
||||
}
|
||||
|
||||
div.body hr {
|
||||
border: 0;
|
||||
background-color: #ccc;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
div.body pre {
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ac9;
|
||||
}
|
||||
|
||||
div.body div.admonition, div.body div.impl-detail {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
div.body div.impl-detail > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.body div.seealso {
|
||||
border: 1px solid #dddd66;
|
||||
}
|
||||
|
||||
div.body a {
|
||||
color: #00608f;
|
||||
}
|
||||
|
||||
div.body a:visited {
|
||||
color: #30306f;
|
||||
}
|
||||
|
||||
div.body a:hover {
|
||||
color: #00B0E4;
|
||||
}
|
||||
|
||||
tt, pre {
|
||||
font-family: monospace, sans-serif;
|
||||
font-size: 96.5%;
|
||||
}
|
||||
|
||||
div.body tt {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
div.body tt.descname {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
div.body tt.xref, div.body a tt {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
p.deprecated {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
table.docutils {
|
||||
border: 1px solid #ddd;
|
||||
min-width: 20%;
|
||||
border-radius: 3px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
border: 1px solid #ddd !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
table p, table li {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
table.docutils th {
|
||||
background-color: #eee;
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
|
||||
table.docutils td {
|
||||
background-color: white;
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
|
||||
table.footnote, table.footnote td {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
line-height: 150%;
|
||||
margin-top: -2em;
|
||||
text-align: right;
|
||||
width: auto;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
div.footer a:hover {
|
||||
color: #0095C4;
|
||||
}
|
||||
|
||||
div.body h1,
|
||||
div.body h2,
|
||||
div.body h3 {
|
||||
background-color: #EAEAEA;
|
||||
border-bottom: 1px solid #CCC;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
padding-left: 5px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
div.body h2 {
|
||||
padding-left:10px;
|
||||
}
|
||||
23
python/psutil/docs/_themes/pydoctheme/theme.conf
vendored
Normal file
23
python/psutil/docs/_themes/pydoctheme/theme.conf
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
[theme]
|
||||
inherit = default
|
||||
stylesheet = pydoctheme.css
|
||||
pygments_style = sphinx
|
||||
|
||||
[options]
|
||||
bodyfont = 'Lucida Grande', 'Lucida Sans', 'DejaVu Sans', Arial, sans-serif
|
||||
headfont = 'Lucida Grande', 'Lucida Sans', 'DejaVu Sans', Arial, sans-serif
|
||||
footerbgcolor = white
|
||||
footertextcolor = #555555
|
||||
relbarbgcolor = white
|
||||
relbartextcolor = #666666
|
||||
relbarlinkcolor = #444444
|
||||
sidebarbgcolor = white
|
||||
sidebartextcolor = #444444
|
||||
sidebarlinkcolor = #444444
|
||||
bgcolor = white
|
||||
textcolor = #222222
|
||||
linkcolor = #0090c0
|
||||
visitedlinkcolor = #00608f
|
||||
headtextcolor = #1a1a1a
|
||||
headbgcolor = white
|
||||
headlinkcolor = #aaaaaa
|
||||
248
python/psutil/docs/conf.py
Normal file
248
python/psutil/docs/conf.py
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# psutil documentation build configuration file, created by
|
||||
# sphinx-quickstart.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import datetime
|
||||
import os
|
||||
|
||||
|
||||
PROJECT_NAME = "psutil"
|
||||
AUTHOR = "Giampaolo Rodola'"
|
||||
THIS_YEAR = str(datetime.datetime.now().year)
|
||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
def get_version():
|
||||
INIT = os.path.abspath(os.path.join(HERE, '../psutil/__init__.py'))
|
||||
with open(INIT, 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith('__version__'):
|
||||
ret = eval(line.strip().split(' = ')[1])
|
||||
assert ret.count('.') == 2, ret
|
||||
for num in ret.split('.'):
|
||||
assert num.isdigit(), ret
|
||||
return ret
|
||||
else:
|
||||
raise ValueError("couldn't find version string")
|
||||
|
||||
VERSION = get_version()
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.autodoc',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.pngmath',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.intersphinx']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_template']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
# source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = PROJECT_NAME
|
||||
copyright = '2009-%s, %s' % (THIS_YEAR, AUTHOR)
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = VERSION
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
# language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
# today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
# today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
# default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
# add_module_names = True
|
||||
|
||||
autodoc_docstring_signature = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
# show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
# modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
html_theme = 'pydoctheme'
|
||||
html_theme_options = {'collapsiblesidebar': True}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = ["_themes"]
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
html_title = "{project} {version} documentation".format(**locals())
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
# html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
# html_logo = 'logo.png'
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
html_favicon = '_static/favicon.ico'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
html_sidebars = {
|
||||
'index': 'indexsidebar.html',
|
||||
'**': ['globaltoc.html',
|
||||
'relations.html',
|
||||
'sourcelink.html',
|
||||
'searchbox.html']
|
||||
}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
# html_additional_pages = {
|
||||
# 'index': 'indexcontent.html',
|
||||
# }
|
||||
|
||||
# If false, no module index is generated.
|
||||
html_domain_indices = False
|
||||
|
||||
# If false, no index is generated.
|
||||
html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
# html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
# html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
# html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
# html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%s-doc' % PROJECT_NAME
|
||||
|
||||
# -- Options for LaTeX output ------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
# latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
# latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', '%s.tex' % PROJECT_NAME,
|
||||
'%s documentation' % PROJECT_NAME, AUTHOR),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at
|
||||
# the top of the title page.
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
# latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
# latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
# latex_show_urls = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
# latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
# latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
# latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', PROJECT_NAME, '%s documentation' % PROJECT_NAME, [AUTHOR], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
# man_show_urls = False
|
||||
1400
python/psutil/docs/index.rst
Normal file
1400
python/psutil/docs/index.rst
Normal file
File diff suppressed because it is too large
Load diff
242
python/psutil/docs/make.bat
Normal file
242
python/psutil/docs/make.bat
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. devhelp to make HTML files and a Devhelp project
|
||||
echo. epub to make an epub
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. text to make text files
|
||||
echo. man to make manual pages
|
||||
echo. texinfo to make Texinfo files
|
||||
echo. gettext to make PO message catalogs
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. xml to make Docutils-native XML files
|
||||
echo. pseudoxml to make pseudoxml-XML files for display purposes
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
|
||||
%SPHINXBUILD% 2> nul
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "singlehtml" (
|
||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\psutil.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\psutil.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "devhelp" (
|
||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub" (
|
||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdf" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf
|
||||
cd %BUILDDIR%/..
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdfja" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf-ja
|
||||
cd %BUILDDIR%/..
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "text" (
|
||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "man" (
|
||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "texinfo" (
|
||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "gettext" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "xml" (
|
||||
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The XML files are in %BUILDDIR%/xml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pseudoxml" (
|
||||
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
||||
11
python/psutil/docs/xxx
Normal file
11
python/psutil/docs/xxx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
cpu 1974613 1749 485728 6305758 80280 15 5924 0 0 0
|
||||
|
||||
cpu0 519156 374 132999 5977865 72925 10 1458 0 0 0
|
||||
|
||||
cpu1 524667 401 125931 108960 2110 4 2214 0 0 0
|
||||
|
||||
cpu2 462286 520 117046 109514 2666 0 828 0 0 0
|
||||
|
||||
cpu3 468502 453 109750 109418 2578 0 1424 0 0 0
|
||||
|
||||
|
||||
62
python/psutil/examples/disk_usage.py
Normal file
62
python/psutil/examples/disk_usage.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
List all mounted disk partitions a-la "df -h" command.
|
||||
|
||||
$ python examples/disk_usage.py
|
||||
Device Total Used Free Use % Type Mount
|
||||
/dev/sdb3 18.9G 14.7G 3.3G 77% ext4 /
|
||||
/dev/sda6 345.9G 83.8G 244.5G 24% ext4 /home
|
||||
/dev/sda1 296.0M 43.1M 252.9M 14% vfat /boot/efi
|
||||
/dev/sda2 600.0M 312.4M 287.6M 52% fuseblk /media/Recovery
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import psutil
|
||||
|
||||
|
||||
def bytes2human(n):
|
||||
# http://code.activestate.com/recipes/578019
|
||||
# >>> bytes2human(10000)
|
||||
# '9.8K'
|
||||
# >>> bytes2human(100001221)
|
||||
# '95.4M'
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for s in reversed(symbols):
|
||||
if n >= prefix[s]:
|
||||
value = float(n) / prefix[s]
|
||||
return '%.1f%s' % (value, s)
|
||||
return "%sB" % n
|
||||
|
||||
|
||||
def main():
|
||||
templ = "%-17s %8s %8s %8s %5s%% %9s %s"
|
||||
print(templ % ("Device", "Total", "Used", "Free", "Use ", "Type",
|
||||
"Mount"))
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
if os.name == 'nt':
|
||||
if 'cdrom' in part.opts or part.fstype == '':
|
||||
# skip cd-rom drives with no disk in it; they may raise
|
||||
# ENOENT, pop-up a Windows GUI error for a non-ready
|
||||
# partition or just hang.
|
||||
continue
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
print(templ % (
|
||||
part.device,
|
||||
bytes2human(usage.total),
|
||||
bytes2human(usage.used),
|
||||
bytes2human(usage.free),
|
||||
int(usage.percent),
|
||||
part.fstype,
|
||||
part.mountpoint))
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
41
python/psutil/examples/free.py
Normal file
41
python/psutil/examples/free.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A clone of 'free' cmdline utility.
|
||||
|
||||
$ python examples/free.py
|
||||
total used free shared buffers cache
|
||||
Mem: 10125520 8625996 1499524 0 349500 3307836
|
||||
Swap: 0 0 0
|
||||
"""
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
def main():
|
||||
virt = psutil.virtual_memory()
|
||||
swap = psutil.swap_memory()
|
||||
templ = "%-7s %10s %10s %10s %10s %10s %10s"
|
||||
print(templ % ('', 'total', 'used', 'free', 'shared', 'buffers', 'cache'))
|
||||
print(templ % (
|
||||
'Mem:',
|
||||
int(virt.total / 1024),
|
||||
int(virt.used / 1024),
|
||||
int(virt.free / 1024),
|
||||
int(getattr(virt, 'shared', 0) / 1024),
|
||||
int(getattr(virt, 'buffers', 0) / 1024),
|
||||
int(getattr(virt, 'cached', 0) / 1024)))
|
||||
print(templ % (
|
||||
'Swap:', int(swap.total / 1024),
|
||||
int(swap.used / 1024),
|
||||
int(swap.free / 1024),
|
||||
'',
|
||||
'',
|
||||
''))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
78
python/psutil/examples/ifconfig.py
Normal file
78
python/psutil/examples/ifconfig.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A clone of 'ifconfig' on UNIX.
|
||||
|
||||
$ python examples/ifconfig.py
|
||||
lo (speed=0MB, duplex=?, mtu=65536, up=yes):
|
||||
IPv4 address : 127.0.0.1
|
||||
broadcast : 127.0.0.1
|
||||
netmask : 255.0.0.0
|
||||
IPv6 address : ::1
|
||||
netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
MAC address : 00:00:00:00:00:00
|
||||
broadcast : 00:00:00:00:00:00
|
||||
|
||||
wlan0 (speed=0MB, duplex=?, mtu=1500, up=yes):
|
||||
IPv4 address : 10.0.3.1
|
||||
broadcast : 10.0.3.255
|
||||
netmask : 255.255.255.0
|
||||
IPv6 address : fe80::3005:adff:fe31:8698
|
||||
netmask : ffff:ffff:ffff:ffff::
|
||||
MAC address : 32:05:ad:31:86:98
|
||||
broadcast : ff:ff:ff:ff:ff:ff
|
||||
|
||||
eth0 (speed=100MB, duplex=full, mtu=1500, up=yes):
|
||||
IPv4 address : 192.168.1.2
|
||||
broadcast : 192.168.1.255
|
||||
netmask : 255.255.255.0
|
||||
IPv6 address : fe80::c685:8ff:fe45:641
|
||||
netmask : ffff:ffff:ffff:ffff::
|
||||
MAC address : c4:85:08:45:06:41
|
||||
broadcast : ff:ff:ff:ff:ff:ff
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import socket
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
af_map = {
|
||||
socket.AF_INET: 'IPv4',
|
||||
socket.AF_INET6: 'IPv6',
|
||||
psutil.AF_LINK: 'MAC',
|
||||
}
|
||||
|
||||
duplex_map = {
|
||||
psutil.NIC_DUPLEX_FULL: "full",
|
||||
psutil.NIC_DUPLEX_HALF: "half",
|
||||
psutil.NIC_DUPLEX_UNKNOWN: "?",
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
stats = psutil.net_if_stats()
|
||||
for nic, addrs in psutil.net_if_addrs().items():
|
||||
if nic in stats:
|
||||
print("%s (speed=%sMB, duplex=%s, mtu=%s, up=%s):" % (
|
||||
nic, stats[nic].speed, duplex_map[stats[nic].duplex],
|
||||
stats[nic].mtu, "yes" if stats[nic].isup else "no"))
|
||||
else:
|
||||
print("%s:" % (nic))
|
||||
for addr in addrs:
|
||||
print(" %-8s" % af_map.get(addr.family, addr.family), end="")
|
||||
print(" address : %s" % addr.address)
|
||||
if addr.broadcast:
|
||||
print(" broadcast : %s" % addr.broadcast)
|
||||
if addr.netmask:
|
||||
print(" netmask : %s" % addr.netmask)
|
||||
print("")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
179
python/psutil/examples/iotop.py
Normal file
179
python/psutil/examples/iotop.py
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A clone of iotop (http://guichaz.free.fr/iotop/) showing real time
|
||||
disk I/O statistics.
|
||||
|
||||
It works on Linux only (FreeBSD and OSX are missing support for IO
|
||||
counters).
|
||||
It doesn't work on Windows as curses module is required.
|
||||
|
||||
Example output:
|
||||
|
||||
$ python examples/iotop.py
|
||||
Total DISK READ: 0.00 B/s | Total DISK WRITE: 472.00 K/s
|
||||
PID USER DISK READ DISK WRITE COMMAND
|
||||
13155 giampao 0.00 B/s 428.00 K/s /usr/bin/google-chrome-beta
|
||||
3260 giampao 0.00 B/s 0.00 B/s bash
|
||||
3779 giampao 0.00 B/s 0.00 B/s gnome-session --session=ubuntu
|
||||
3830 giampao 0.00 B/s 0.00 B/s /usr/bin/dbus-launch
|
||||
3831 giampao 0.00 B/s 0.00 B/s //bin/dbus-daemon --fork --print-pid 5
|
||||
3841 giampao 0.00 B/s 0.00 B/s /usr/lib/at-spi-bus-launcher
|
||||
3845 giampao 0.00 B/s 0.00 B/s /bin/dbus-daemon
|
||||
3848 giampao 0.00 B/s 0.00 B/s /usr/lib/at-spi2-core/at-spi2-registryd
|
||||
3862 giampao 0.00 B/s 0.00 B/s /usr/lib/gnome-settings-daemon
|
||||
|
||||
Author: Giampaolo Rodola' <g.rodola@gmail.com>
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import time
|
||||
import sys
|
||||
try:
|
||||
import curses
|
||||
except ImportError:
|
||||
sys.exit('platform not supported')
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
# --- curses stuff
|
||||
def tear_down():
|
||||
win.keypad(0)
|
||||
curses.nocbreak()
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
|
||||
win = curses.initscr()
|
||||
atexit.register(tear_down)
|
||||
curses.endwin()
|
||||
lineno = 0
|
||||
|
||||
|
||||
def print_line(line, highlight=False):
|
||||
"""A thin wrapper around curses's addstr()."""
|
||||
global lineno
|
||||
try:
|
||||
if highlight:
|
||||
line += " " * (win.getmaxyx()[1] - len(line))
|
||||
win.addstr(lineno, 0, line, curses.A_REVERSE)
|
||||
else:
|
||||
win.addstr(lineno, 0, line, 0)
|
||||
except curses.error:
|
||||
lineno = 0
|
||||
win.refresh()
|
||||
raise
|
||||
else:
|
||||
lineno += 1
|
||||
# --- /curses stuff
|
||||
|
||||
|
||||
def bytes2human(n):
|
||||
"""
|
||||
>>> bytes2human(10000)
|
||||
'9.8 K/s'
|
||||
>>> bytes2human(100001221)
|
||||
'95.4 M/s'
|
||||
"""
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for s in reversed(symbols):
|
||||
if n >= prefix[s]:
|
||||
value = float(n) / prefix[s]
|
||||
return '%.2f %s/s' % (value, s)
|
||||
return '%.2f B/s' % (n)
|
||||
|
||||
|
||||
def poll(interval):
|
||||
"""Calculate IO usage by comparing IO statics before and
|
||||
after the interval.
|
||||
Return a tuple including all currently running processes
|
||||
sorted by IO activity and total disks I/O activity.
|
||||
"""
|
||||
# first get a list of all processes and disk io counters
|
||||
procs = [p for p in psutil.process_iter()]
|
||||
for p in procs[:]:
|
||||
try:
|
||||
p._before = p.io_counters()
|
||||
except psutil.Error:
|
||||
procs.remove(p)
|
||||
continue
|
||||
disks_before = psutil.disk_io_counters()
|
||||
|
||||
# sleep some time
|
||||
time.sleep(interval)
|
||||
|
||||
# then retrieve the same info again
|
||||
for p in procs[:]:
|
||||
try:
|
||||
p._after = p.io_counters()
|
||||
p._cmdline = ' '.join(p.cmdline())
|
||||
if not p._cmdline:
|
||||
p._cmdline = p.name()
|
||||
p._username = p.username()
|
||||
except (psutil.NoSuchProcess, psutil.ZombieProcess):
|
||||
procs.remove(p)
|
||||
disks_after = psutil.disk_io_counters()
|
||||
|
||||
# finally calculate results by comparing data before and
|
||||
# after the interval
|
||||
for p in procs:
|
||||
p._read_per_sec = p._after.read_bytes - p._before.read_bytes
|
||||
p._write_per_sec = p._after.write_bytes - p._before.write_bytes
|
||||
p._total = p._read_per_sec + p._write_per_sec
|
||||
|
||||
disks_read_per_sec = disks_after.read_bytes - disks_before.read_bytes
|
||||
disks_write_per_sec = disks_after.write_bytes - disks_before.write_bytes
|
||||
|
||||
# sort processes by total disk IO so that the more intensive
|
||||
# ones get listed first
|
||||
processes = sorted(procs, key=lambda p: p._total, reverse=True)
|
||||
|
||||
return (processes, disks_read_per_sec, disks_write_per_sec)
|
||||
|
||||
|
||||
def refresh_window(procs, disks_read, disks_write):
|
||||
"""Print results on screen by using curses."""
|
||||
curses.endwin()
|
||||
templ = "%-5s %-7s %11s %11s %s"
|
||||
win.erase()
|
||||
|
||||
disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \
|
||||
% (bytes2human(disks_read), bytes2human(disks_write))
|
||||
print_line(disks_tot)
|
||||
|
||||
header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND")
|
||||
print_line(header, highlight=True)
|
||||
|
||||
for p in procs:
|
||||
line = templ % (
|
||||
p.pid,
|
||||
p._username[:7],
|
||||
bytes2human(p._read_per_sec),
|
||||
bytes2human(p._write_per_sec),
|
||||
p._cmdline)
|
||||
try:
|
||||
print_line(line)
|
||||
except curses.error:
|
||||
break
|
||||
win.refresh()
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
interval = 0
|
||||
while True:
|
||||
args = poll(interval)
|
||||
refresh_window(*args)
|
||||
interval = 1
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
32
python/psutil/examples/killall.py
Normal file
32
python/psutil/examples/killall.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
Kill a process by name.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import psutil
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit('usage: %s name' % __file__)
|
||||
else:
|
||||
NAME = sys.argv[1]
|
||||
|
||||
killed = []
|
||||
for proc in psutil.process_iter():
|
||||
if proc.name() == NAME and proc.pid != os.getpid():
|
||||
proc.kill()
|
||||
killed.append(proc.pid)
|
||||
if not killed:
|
||||
sys.exit('%s: no process found' % NAME)
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
sys.exit(main())
|
||||
68
python/psutil/examples/meminfo.py
Normal file
68
python/psutil/examples/meminfo.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
Print system memory information.
|
||||
|
||||
$ python examples/meminfo.py
|
||||
MEMORY
|
||||
------
|
||||
Total : 9.7G
|
||||
Available : 4.9G
|
||||
Percent : 49.0
|
||||
Used : 8.2G
|
||||
Free : 1.4G
|
||||
Active : 5.6G
|
||||
Inactive : 2.1G
|
||||
Buffers : 341.2M
|
||||
Cached : 3.2G
|
||||
|
||||
SWAP
|
||||
----
|
||||
Total : 0B
|
||||
Used : 0B
|
||||
Free : 0B
|
||||
Percent : 0.0
|
||||
Sin : 0B
|
||||
Sout : 0B
|
||||
"""
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
def bytes2human(n):
|
||||
# http://code.activestate.com/recipes/578019
|
||||
# >>> bytes2human(10000)
|
||||
# '9.8K'
|
||||
# >>> bytes2human(100001221)
|
||||
# '95.4M'
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for s in reversed(symbols):
|
||||
if n >= prefix[s]:
|
||||
value = float(n) / prefix[s]
|
||||
return '%.1f%s' % (value, s)
|
||||
return "%sB" % n
|
||||
|
||||
|
||||
def pprint_ntuple(nt):
|
||||
for name in nt._fields:
|
||||
value = getattr(nt, name)
|
||||
if name != 'percent':
|
||||
value = bytes2human(value)
|
||||
print('%-10s : %7s' % (name.capitalize(), value))
|
||||
|
||||
|
||||
def main():
|
||||
print('MEMORY\n------')
|
||||
pprint_ntuple(psutil.virtual_memory())
|
||||
print('\nSWAP\n----')
|
||||
pprint_ntuple(psutil.swap_memory())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
64
python/psutil/examples/netstat.py
Normal file
64
python/psutil/examples/netstat.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A clone of 'netstat -antp' on Linux.
|
||||
|
||||
$ python examples/netstat.py
|
||||
Proto Local address Remote address Status PID Program name
|
||||
tcp 127.0.0.1:48256 127.0.0.1:45884 ESTABLISHED 13646 chrome
|
||||
tcp 127.0.0.1:47073 127.0.0.1:45884 ESTABLISHED 13646 chrome
|
||||
tcp 127.0.0.1:47072 127.0.0.1:45884 ESTABLISHED 13646 chrome
|
||||
tcp 127.0.0.1:45884 - LISTEN 13651 GoogleTalkPlugi
|
||||
tcp 127.0.0.1:60948 - LISTEN 13651 GoogleTalkPlugi
|
||||
tcp 172.17.42.1:49102 127.0.0.1:19305 CLOSE_WAIT 13651 GoogleTalkPlugi
|
||||
tcp 172.17.42.1:55797 127.0.0.1:443 CLOSE_WAIT 13651 GoogleTalkPlugi
|
||||
...
|
||||
"""
|
||||
|
||||
import socket
|
||||
from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
AD = "-"
|
||||
AF_INET6 = getattr(socket, 'AF_INET6', object())
|
||||
proto_map = {
|
||||
(AF_INET, SOCK_STREAM): 'tcp',
|
||||
(AF_INET6, SOCK_STREAM): 'tcp6',
|
||||
(AF_INET, SOCK_DGRAM): 'udp',
|
||||
(AF_INET6, SOCK_DGRAM): 'udp6',
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
templ = "%-5s %-30s %-30s %-13s %-6s %s"
|
||||
print(templ % (
|
||||
"Proto", "Local address", "Remote address", "Status", "PID",
|
||||
"Program name"))
|
||||
proc_names = {}
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
proc_names[p.pid] = p.name()
|
||||
except psutil.Error:
|
||||
pass
|
||||
for c in psutil.net_connections(kind='inet'):
|
||||
laddr = "%s:%s" % (c.laddr)
|
||||
raddr = ""
|
||||
if c.raddr:
|
||||
raddr = "%s:%s" % (c.raddr)
|
||||
print(templ % (
|
||||
proto_map[(c.family, c.type)],
|
||||
laddr,
|
||||
raddr or AD,
|
||||
c.status,
|
||||
c.pid or AD,
|
||||
proc_names.get(c.pid, '?')[:15],
|
||||
))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
165
python/psutil/examples/nettop.py
Normal file
165
python/psutil/examples/nettop.py
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# $Id: iotop.py 1160 2011-10-14 18:50:36Z g.rodola@gmail.com $
|
||||
#
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
Shows real-time network statistics.
|
||||
|
||||
Author: Giampaolo Rodola' <g.rodola@gmail.com>
|
||||
|
||||
$ python examples/nettop.py
|
||||
-----------------------------------------------------------
|
||||
total bytes: sent: 1.49 G received: 4.82 G
|
||||
total packets: sent: 7338724 received: 8082712
|
||||
|
||||
wlan0 TOTAL PER-SEC
|
||||
-----------------------------------------------------------
|
||||
bytes-sent 1.29 G 0.00 B/s
|
||||
bytes-recv 3.48 G 0.00 B/s
|
||||
pkts-sent 7221782 0
|
||||
pkts-recv 6753724 0
|
||||
|
||||
eth1 TOTAL PER-SEC
|
||||
-----------------------------------------------------------
|
||||
bytes-sent 131.77 M 0.00 B/s
|
||||
bytes-recv 1.28 G 0.00 B/s
|
||||
pkts-sent 0 0
|
||||
pkts-recv 1214470 0
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import time
|
||||
import sys
|
||||
try:
|
||||
import curses
|
||||
except ImportError:
|
||||
sys.exit('platform not supported')
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
# --- curses stuff
|
||||
def tear_down():
|
||||
win.keypad(0)
|
||||
curses.nocbreak()
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
|
||||
win = curses.initscr()
|
||||
atexit.register(tear_down)
|
||||
curses.endwin()
|
||||
lineno = 0
|
||||
|
||||
|
||||
def print_line(line, highlight=False):
|
||||
"""A thin wrapper around curses's addstr()."""
|
||||
global lineno
|
||||
try:
|
||||
if highlight:
|
||||
line += " " * (win.getmaxyx()[1] - len(line))
|
||||
win.addstr(lineno, 0, line, curses.A_REVERSE)
|
||||
else:
|
||||
win.addstr(lineno, 0, line, 0)
|
||||
except curses.error:
|
||||
lineno = 0
|
||||
win.refresh()
|
||||
raise
|
||||
else:
|
||||
lineno += 1
|
||||
# --- curses stuff
|
||||
|
||||
|
||||
def bytes2human(n):
|
||||
"""
|
||||
>>> bytes2human(10000)
|
||||
'9.8 K'
|
||||
>>> bytes2human(100001221)
|
||||
'95.4 M'
|
||||
"""
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for s in reversed(symbols):
|
||||
if n >= prefix[s]:
|
||||
value = float(n) / prefix[s]
|
||||
return '%.2f %s' % (value, s)
|
||||
return '%.2f B' % (n)
|
||||
|
||||
|
||||
def poll(interval):
|
||||
"""Retrieve raw stats within an interval window."""
|
||||
tot_before = psutil.net_io_counters()
|
||||
pnic_before = psutil.net_io_counters(pernic=True)
|
||||
# sleep some time
|
||||
time.sleep(interval)
|
||||
tot_after = psutil.net_io_counters()
|
||||
pnic_after = psutil.net_io_counters(pernic=True)
|
||||
return (tot_before, tot_after, pnic_before, pnic_after)
|
||||
|
||||
|
||||
def refresh_window(tot_before, tot_after, pnic_before, pnic_after):
|
||||
"""Print stats on screen."""
|
||||
global lineno
|
||||
|
||||
# totals
|
||||
print_line("total bytes: sent: %-10s received: %s" % (
|
||||
bytes2human(tot_after.bytes_sent),
|
||||
bytes2human(tot_after.bytes_recv))
|
||||
)
|
||||
print_line("total packets: sent: %-10s received: %s" % (
|
||||
tot_after.packets_sent, tot_after.packets_recv))
|
||||
|
||||
# per-network interface details: let's sort network interfaces so
|
||||
# that the ones which generated more traffic are shown first
|
||||
print_line("")
|
||||
nic_names = list(pnic_after.keys())
|
||||
nic_names.sort(key=lambda x: sum(pnic_after[x]), reverse=True)
|
||||
for name in nic_names:
|
||||
stats_before = pnic_before[name]
|
||||
stats_after = pnic_after[name]
|
||||
templ = "%-15s %15s %15s"
|
||||
print_line(templ % (name, "TOTAL", "PER-SEC"), highlight=True)
|
||||
print_line(templ % (
|
||||
"bytes-sent",
|
||||
bytes2human(stats_after.bytes_sent),
|
||||
bytes2human(
|
||||
stats_after.bytes_sent - stats_before.bytes_sent) + '/s',
|
||||
))
|
||||
print_line(templ % (
|
||||
"bytes-recv",
|
||||
bytes2human(stats_after.bytes_recv),
|
||||
bytes2human(
|
||||
stats_after.bytes_recv - stats_before.bytes_recv) + '/s',
|
||||
))
|
||||
print_line(templ % (
|
||||
"pkts-sent",
|
||||
stats_after.packets_sent,
|
||||
stats_after.packets_sent - stats_before.packets_sent,
|
||||
))
|
||||
print_line(templ % (
|
||||
"pkts-recv",
|
||||
stats_after.packets_recv,
|
||||
stats_after.packets_recv - stats_before.packets_recv,
|
||||
))
|
||||
print_line("")
|
||||
win.refresh()
|
||||
lineno = 0
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
interval = 0
|
||||
while True:
|
||||
args = poll(interval)
|
||||
refresh_window(*args)
|
||||
interval = 1
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
53
python/psutil/examples/pidof.py
Normal file
53
python/psutil/examples/pidof.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola', karthikrev. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
|
||||
"""
|
||||
A clone of 'pidof' cmdline utility.
|
||||
$ pidof python
|
||||
1140 1138 1136 1134 1133 1129 1127 1125 1121 1120 1119
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import psutil
|
||||
import sys
|
||||
|
||||
|
||||
def pidof(pgname):
|
||||
pids = []
|
||||
for proc in psutil.process_iter():
|
||||
# search for matches in the process name and cmdline
|
||||
try:
|
||||
name = proc.name()
|
||||
except psutil.Error:
|
||||
pass
|
||||
else:
|
||||
if name == pgname:
|
||||
pids.append(str(proc.pid))
|
||||
continue
|
||||
|
||||
try:
|
||||
cmdline = proc.cmdline()
|
||||
except psutil.Error:
|
||||
pass
|
||||
else:
|
||||
if cmdline and cmdline[0] == pgname:
|
||||
pids.append(str(proc.pid))
|
||||
|
||||
return pids
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit('usage: %s pgname' % __file__)
|
||||
else:
|
||||
pgname = sys.argv[1]
|
||||
pids = pidof(pgname)
|
||||
if pids:
|
||||
print(" ".join(pids))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
57
python/psutil/examples/pmap.py
Normal file
57
python/psutil/examples/pmap.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A clone of 'pmap' utility on Linux, 'vmmap' on OSX and 'procstat -v' on BSD.
|
||||
Report memory map of a process.
|
||||
|
||||
$ python examples/pmap.py 32402
|
||||
pid=32402, name=hg
|
||||
Address RSS Mode Mapping
|
||||
0000000000400000 1200K r-xp /usr/bin/python2.7
|
||||
0000000000838000 4K r--p /usr/bin/python2.7
|
||||
0000000000839000 304K rw-p /usr/bin/python2.7
|
||||
00000000008ae000 68K rw-p [anon]
|
||||
000000000275e000 5396K rw-p [heap]
|
||||
00002b29bb1e0000 124K r-xp /lib/x86_64-linux-gnu/ld-2.17.so
|
||||
00002b29bb203000 8K rw-p [anon]
|
||||
00002b29bb220000 528K rw-p [anon]
|
||||
00002b29bb2d8000 768K rw-p [anon]
|
||||
00002b29bb402000 4K r--p /lib/x86_64-linux-gnu/ld-2.17.so
|
||||
00002b29bb403000 8K rw-p /lib/x86_64-linux-gnu/ld-2.17.so
|
||||
00002b29bb405000 60K r-xp /lib/x86_64-linux-gnu/libpthread-2.17.so
|
||||
00002b29bb41d000 0K ---p /lib/x86_64-linux-gnu/libpthread-2.17.so
|
||||
00007fff94be6000 48K rw-p [stack]
|
||||
00007fff94dd1000 4K r-xp [vdso]
|
||||
ffffffffff600000 0K r-xp [vsyscall]
|
||||
...
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit('usage: pmap <pid>')
|
||||
p = psutil.Process(int(sys.argv[1]))
|
||||
print("pid=%s, name=%s" % (p.pid, p.name()))
|
||||
templ = "%-16s %10s %-7s %s"
|
||||
print(templ % ("Address", "RSS", "Mode", "Mapping"))
|
||||
total_rss = 0
|
||||
for m in p.memory_maps(grouped=False):
|
||||
total_rss += m.rss
|
||||
print(templ % (
|
||||
m.addr.split('-')[0].zfill(16),
|
||||
str(m.rss / 1024) + 'K',
|
||||
m.perms,
|
||||
m.path))
|
||||
print("-" * 33)
|
||||
print(templ % ("Total", str(total_rss / 1024) + 'K', '', ''))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
167
python/psutil/examples/process_detail.py
Normal file
167
python/psutil/examples/process_detail.py
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
Print detailed information about a process.
|
||||
Author: Giampaolo Rodola' <g.rodola@gmail.com>
|
||||
|
||||
$ python examples/process_detail.py
|
||||
pid 820
|
||||
name python
|
||||
exe /usr/bin/python2.7
|
||||
parent 29613 (bash)
|
||||
cmdline python examples/process_detail.py
|
||||
started 2014-41-27 03:41
|
||||
user giampaolo
|
||||
uids real=1000, effective=1000, saved=1000
|
||||
gids real=1000, effective=1000, saved=1000
|
||||
terminal /dev/pts/17
|
||||
cwd /ssd/svn/psutil
|
||||
memory 0.1% (resident=10.6M, virtual=58.5M)
|
||||
cpu 0.0% (user=0.09, system=0.0)
|
||||
status running
|
||||
niceness 0
|
||||
num threads 1
|
||||
I/O bytes-read=0B, bytes-written=0B
|
||||
open files
|
||||
running threads id=820, user-time=0.09, sys-time=0.0
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
POSIX = os.name == 'posix'
|
||||
|
||||
|
||||
def convert_bytes(n):
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for s in reversed(symbols):
|
||||
if n >= prefix[s]:
|
||||
value = float(n) / prefix[s]
|
||||
return '%.1f%s' % (value, s)
|
||||
return "%sB" % n
|
||||
|
||||
|
||||
def print_(a, b):
|
||||
if sys.stdout.isatty() and POSIX:
|
||||
fmt = '\x1b[1;32m%-17s\x1b[0m %s' % (a, b)
|
||||
else:
|
||||
fmt = '%-15s %s' % (a, b)
|
||||
# python 2/3 compatibility layer
|
||||
sys.stdout.write(fmt + '\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def run(pid):
|
||||
ACCESS_DENIED = ''
|
||||
try:
|
||||
p = psutil.Process(pid)
|
||||
pinfo = p.as_dict(ad_value=ACCESS_DENIED)
|
||||
except psutil.NoSuchProcess as err:
|
||||
sys.exit(str(err))
|
||||
|
||||
try:
|
||||
parent = p.parent()
|
||||
if parent:
|
||||
parent = '(%s)' % parent.name()
|
||||
else:
|
||||
parent = ''
|
||||
except psutil.Error:
|
||||
parent = ''
|
||||
if pinfo['create_time'] != ACCESS_DENIED:
|
||||
started = datetime.datetime.fromtimestamp(
|
||||
pinfo['create_time']).strftime('%Y-%m-%d %H:%M')
|
||||
else:
|
||||
started = ACCESS_DENIED
|
||||
io = pinfo.get('io_counters', ACCESS_DENIED)
|
||||
if pinfo['memory_info'] != ACCESS_DENIED:
|
||||
mem = '%s%% (resident=%s, virtual=%s) ' % (
|
||||
round(pinfo['memory_percent'], 1),
|
||||
convert_bytes(pinfo['memory_info'].rss),
|
||||
convert_bytes(pinfo['memory_info'].vms))
|
||||
else:
|
||||
mem = ACCESS_DENIED
|
||||
children = p.children()
|
||||
|
||||
print_('pid', pinfo['pid'])
|
||||
print_('name', pinfo['name'])
|
||||
print_('exe', pinfo['exe'])
|
||||
print_('parent', '%s %s' % (pinfo['ppid'], parent))
|
||||
print_('cmdline', ' '.join(pinfo['cmdline']))
|
||||
print_('started', started)
|
||||
print_('user', pinfo['username'])
|
||||
if POSIX and pinfo['uids'] and pinfo['gids']:
|
||||
print_('uids', 'real=%s, effective=%s, saved=%s' % pinfo['uids'])
|
||||
if POSIX and pinfo['gids']:
|
||||
print_('gids', 'real=%s, effective=%s, saved=%s' % pinfo['gids'])
|
||||
if POSIX:
|
||||
print_('terminal', pinfo['terminal'] or '')
|
||||
print_('cwd', pinfo['cwd'])
|
||||
print_('memory', mem)
|
||||
print_('cpu', '%s%% (user=%s, system=%s)' % (
|
||||
pinfo['cpu_percent'],
|
||||
getattr(pinfo['cpu_times'], 'user', '?'),
|
||||
getattr(pinfo['cpu_times'], 'system', '?')))
|
||||
print_('status', pinfo['status'])
|
||||
print_('niceness', pinfo['nice'])
|
||||
print_('num threads', pinfo['num_threads'])
|
||||
if io != ACCESS_DENIED:
|
||||
print_('I/O', 'bytes-read=%s, bytes-written=%s' % (
|
||||
convert_bytes(io.read_bytes),
|
||||
convert_bytes(io.write_bytes)))
|
||||
if children:
|
||||
print_('children', '')
|
||||
for child in children:
|
||||
print_('', 'pid=%s name=%s' % (child.pid, child.name()))
|
||||
|
||||
if pinfo['open_files'] != ACCESS_DENIED:
|
||||
print_('open files', '')
|
||||
for file in pinfo['open_files']:
|
||||
print_('', 'fd=%s %s ' % (file.fd, file.path))
|
||||
|
||||
if pinfo['threads']:
|
||||
print_('running threads', '')
|
||||
for thread in pinfo['threads']:
|
||||
print_('', 'id=%s, user-time=%s, sys-time=%s' % (
|
||||
thread.id, thread.user_time, thread.system_time))
|
||||
if pinfo['connections'] not in (ACCESS_DENIED, []):
|
||||
print_('open connections', '')
|
||||
for conn in pinfo['connections']:
|
||||
if conn.type == socket.SOCK_STREAM:
|
||||
type = 'TCP'
|
||||
elif conn.type == socket.SOCK_DGRAM:
|
||||
type = 'UDP'
|
||||
else:
|
||||
type = 'UNIX'
|
||||
lip, lport = conn.laddr
|
||||
if not conn.raddr:
|
||||
rip, rport = '*', '*'
|
||||
else:
|
||||
rip, rport = conn.raddr
|
||||
print_('', '%s:%s -> %s:%s type=%s status=%s' % (
|
||||
lip, lport, rip, rport, type, conn.status))
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
if len(argv) == 1:
|
||||
sys.exit(run(os.getpid()))
|
||||
elif len(argv) == 2:
|
||||
sys.exit(run(int(argv[1])))
|
||||
else:
|
||||
sys.exit('usage: %s [pid]' % __file__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
81
python/psutil/examples/ps.py
Normal file
81
python/psutil/examples/ps.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A clone of 'ps -aux' on UNIX.
|
||||
|
||||
$ python examples/ps.py
|
||||
...
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import time
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
def main():
|
||||
today_day = datetime.date.today()
|
||||
templ = "%-10s %5s %4s %4s %7s %7s %-13s %5s %7s %s"
|
||||
attrs = ['pid', 'cpu_percent', 'memory_percent', 'name', 'cpu_times',
|
||||
'create_time', 'memory_info']
|
||||
if os.name == 'posix':
|
||||
attrs.append('uids')
|
||||
attrs.append('terminal')
|
||||
print(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY",
|
||||
"START", "TIME", "COMMAND"))
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
pinfo = p.as_dict(attrs, ad_value='')
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
else:
|
||||
if pinfo['create_time']:
|
||||
ctime = datetime.datetime.fromtimestamp(pinfo['create_time'])
|
||||
if ctime.date() == today_day:
|
||||
ctime = ctime.strftime("%H:%M")
|
||||
else:
|
||||
ctime = ctime.strftime("%b%d")
|
||||
else:
|
||||
ctime = ''
|
||||
cputime = time.strftime("%M:%S",
|
||||
time.localtime(sum(pinfo['cpu_times'])))
|
||||
try:
|
||||
user = p.username()
|
||||
except KeyError:
|
||||
if os.name == 'posix':
|
||||
if pinfo['uids']:
|
||||
user = str(pinfo['uids'].real)
|
||||
else:
|
||||
user = ''
|
||||
else:
|
||||
raise
|
||||
except psutil.Error:
|
||||
user = ''
|
||||
if os.name == 'nt' and '\\' in user:
|
||||
user = user.split('\\')[1]
|
||||
vms = pinfo['memory_info'] and \
|
||||
int(pinfo['memory_info'].vms / 1024) or '?'
|
||||
rss = pinfo['memory_info'] and \
|
||||
int(pinfo['memory_info'].rss / 1024) or '?'
|
||||
memp = pinfo['memory_percent'] and \
|
||||
round(pinfo['memory_percent'], 1) or '?'
|
||||
print(templ % (
|
||||
user[:10],
|
||||
pinfo['pid'],
|
||||
pinfo['cpu_percent'],
|
||||
memp,
|
||||
vms,
|
||||
rss,
|
||||
pinfo.get('terminal', '') or '?',
|
||||
ctime,
|
||||
cputime,
|
||||
pinfo['name'].strip() or '?'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
71
python/psutil/examples/pstree.py
Normal file
71
python/psutil/examples/pstree.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
Similar to 'ps aux --forest' on Linux, prints the process list
|
||||
as a tree structure.
|
||||
|
||||
$ python examples/pstree.py
|
||||
0 ?
|
||||
|- 1 init
|
||||
| |- 289 cgmanager
|
||||
| |- 616 upstart-socket-bridge
|
||||
| |- 628 rpcbind
|
||||
| |- 892 upstart-file-bridge
|
||||
| |- 907 dbus-daemon
|
||||
| |- 978 avahi-daemon
|
||||
| | `_ 979 avahi-daemon
|
||||
| |- 987 NetworkManager
|
||||
| | |- 2242 dnsmasq
|
||||
| | `_ 10699 dhclient
|
||||
| |- 993 polkitd
|
||||
| |- 1061 getty
|
||||
| |- 1066 su
|
||||
| | `_ 1190 salt-minion...
|
||||
...
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import collections
|
||||
import sys
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
def print_tree(parent, tree, indent=''):
|
||||
try:
|
||||
name = psutil.Process(parent).name()
|
||||
except psutil.Error:
|
||||
name = "?"
|
||||
print(parent, name)
|
||||
if parent not in tree:
|
||||
return
|
||||
children = tree[parent][:-1]
|
||||
for child in children:
|
||||
sys.stdout.write(indent + "|- ")
|
||||
print_tree(child, tree, indent + "| ")
|
||||
child = tree[parent][-1]
|
||||
sys.stdout.write(indent + "`_ ")
|
||||
print_tree(child, tree, indent + " ")
|
||||
|
||||
|
||||
def main():
|
||||
# construct a dict where 'values' are all the processes
|
||||
# having 'key' as their parent
|
||||
tree = collections.defaultdict(list)
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
tree[p.ppid()].append(p.pid)
|
||||
except (psutil.NoSuchProcess, psutil.ZombieProcess):
|
||||
pass
|
||||
# on systems supporting PID 0, PID 0's parent is usually 0
|
||||
if 0 in tree and 0 in tree[0]:
|
||||
tree[0].remove(0)
|
||||
print_tree(min(tree), tree)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
233
python/psutil/examples/top.py
Normal file
233
python/psutil/examples/top.py
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A clone of top / htop.
|
||||
|
||||
Author: Giampaolo Rodola' <g.rodola@gmail.com>
|
||||
|
||||
$ python examples/top.py
|
||||
CPU0 [| ] 4.9%
|
||||
CPU1 [||| ] 7.8%
|
||||
CPU2 [ ] 2.0%
|
||||
CPU3 [||||| ] 13.9%
|
||||
Mem [||||||||||||||||||| ] 49.8% 4920M/9888M
|
||||
Swap [ ] 0.0% 0M/0M
|
||||
Processes: 287 (running=1 sleeping=286)
|
||||
Load average: 0.34 0.54 0.46 Uptime: 3 days, 10:16:37
|
||||
|
||||
PID USER NI VIRT RES CPU% MEM% TIME+ NAME
|
||||
------------------------------------------------------------
|
||||
989 giampaol 0 66M 12M 7.4 0.1 0:00.61 python
|
||||
2083 root 0 506M 159M 6.5 1.6 0:29.26 Xorg
|
||||
4503 giampaol 0 599M 25M 6.5 0.3 3:32.60 gnome-terminal
|
||||
3868 giampaol 0 358M 8M 2.8 0.1 23:12.60 pulseaudio
|
||||
3936 giampaol 0 1G 111M 2.8 1.1 33:41.67 compiz
|
||||
4401 giampaol 0 536M 141M 2.8 1.4 35:42.73 skype
|
||||
4047 giampaol 0 743M 76M 1.8 0.8 42:03.33 unity-panel-service
|
||||
13155 giampaol 0 1G 280M 1.8 2.8 41:57.34 chrome
|
||||
10 root 0 0B 0B 0.9 0.0 4:01.81 rcu_sched
|
||||
339 giampaol 0 1G 113M 0.9 1.1 8:15.73 chrome
|
||||
...
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import atexit
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
try:
|
||||
import curses
|
||||
except ImportError:
|
||||
sys.exit('platform not supported')
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
# --- curses stuff
|
||||
def tear_down():
|
||||
win.keypad(0)
|
||||
curses.nocbreak()
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
|
||||
win = curses.initscr()
|
||||
atexit.register(tear_down)
|
||||
curses.endwin()
|
||||
lineno = 0
|
||||
|
||||
|
||||
def print_line(line, highlight=False):
|
||||
"""A thin wrapper around curses's addstr()."""
|
||||
global lineno
|
||||
try:
|
||||
if highlight:
|
||||
line += " " * (win.getmaxyx()[1] - len(line))
|
||||
win.addstr(lineno, 0, line, curses.A_REVERSE)
|
||||
else:
|
||||
win.addstr(lineno, 0, line, 0)
|
||||
except curses.error:
|
||||
lineno = 0
|
||||
win.refresh()
|
||||
raise
|
||||
else:
|
||||
lineno += 1
|
||||
# --- /curses stuff
|
||||
|
||||
|
||||
def bytes2human(n):
|
||||
"""
|
||||
>>> bytes2human(10000)
|
||||
'9K'
|
||||
>>> bytes2human(100001221)
|
||||
'95M'
|
||||
"""
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for s in reversed(symbols):
|
||||
if n >= prefix[s]:
|
||||
value = int(float(n) / prefix[s])
|
||||
return '%s%s' % (value, s)
|
||||
return "%sB" % n
|
||||
|
||||
|
||||
def poll(interval):
|
||||
# sleep some time
|
||||
time.sleep(interval)
|
||||
procs = []
|
||||
procs_status = {}
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
p.dict = p.as_dict(['username', 'nice', 'memory_info',
|
||||
'memory_percent', 'cpu_percent',
|
||||
'cpu_times', 'name', 'status'])
|
||||
try:
|
||||
procs_status[p.dict['status']] += 1
|
||||
except KeyError:
|
||||
procs_status[p.dict['status']] = 1
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
else:
|
||||
procs.append(p)
|
||||
|
||||
# return processes sorted by CPU percent usage
|
||||
processes = sorted(procs, key=lambda p: p.dict['cpu_percent'],
|
||||
reverse=True)
|
||||
return (processes, procs_status)
|
||||
|
||||
|
||||
def print_header(procs_status, num_procs):
|
||||
"""Print system-related info, above the process list."""
|
||||
|
||||
def get_dashes(perc):
|
||||
dashes = "|" * int((float(perc) / 10 * 4))
|
||||
empty_dashes = " " * (40 - len(dashes))
|
||||
return dashes, empty_dashes
|
||||
|
||||
# cpu usage
|
||||
percs = psutil.cpu_percent(interval=0, percpu=True)
|
||||
for cpu_num, perc in enumerate(percs):
|
||||
dashes, empty_dashes = get_dashes(perc)
|
||||
print_line(" CPU%-2s [%s%s] %5s%%" % (cpu_num, dashes, empty_dashes,
|
||||
perc))
|
||||
mem = psutil.virtual_memory()
|
||||
dashes, empty_dashes = get_dashes(mem.percent)
|
||||
used = mem.total - mem.available
|
||||
line = " Mem [%s%s] %5s%% %6s/%s" % (
|
||||
dashes, empty_dashes,
|
||||
mem.percent,
|
||||
str(int(used / 1024 / 1024)) + "M",
|
||||
str(int(mem.total / 1024 / 1024)) + "M"
|
||||
)
|
||||
print_line(line)
|
||||
|
||||
# swap usage
|
||||
swap = psutil.swap_memory()
|
||||
dashes, empty_dashes = get_dashes(swap.percent)
|
||||
line = " Swap [%s%s] %5s%% %6s/%s" % (
|
||||
dashes, empty_dashes,
|
||||
swap.percent,
|
||||
str(int(swap.used / 1024 / 1024)) + "M",
|
||||
str(int(swap.total / 1024 / 1024)) + "M"
|
||||
)
|
||||
print_line(line)
|
||||
|
||||
# processes number and status
|
||||
st = []
|
||||
for x, y in procs_status.items():
|
||||
if y:
|
||||
st.append("%s=%s" % (x, y))
|
||||
st.sort(key=lambda x: x[:3] in ('run', 'sle'), reverse=1)
|
||||
print_line(" Processes: %s (%s)" % (num_procs, ' '.join(st)))
|
||||
# load average, uptime
|
||||
uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time())
|
||||
av1, av2, av3 = os.getloadavg()
|
||||
line = " Load average: %.2f %.2f %.2f Uptime: %s" \
|
||||
% (av1, av2, av3, str(uptime).split('.')[0])
|
||||
print_line(line)
|
||||
|
||||
|
||||
def refresh_window(procs, procs_status):
|
||||
"""Print results on screen by using curses."""
|
||||
curses.endwin()
|
||||
templ = "%-6s %-8s %4s %5s %5s %6s %4s %9s %2s"
|
||||
win.erase()
|
||||
header = templ % ("PID", "USER", "NI", "VIRT", "RES", "CPU%", "MEM%",
|
||||
"TIME+", "NAME")
|
||||
print_header(procs_status, len(procs))
|
||||
print_line("")
|
||||
print_line(header, highlight=True)
|
||||
for p in procs:
|
||||
# TIME+ column shows process CPU cumulative time and it
|
||||
# is expressed as: "mm:ss.ms"
|
||||
if p.dict['cpu_times'] is not None:
|
||||
ctime = timedelta(seconds=sum(p.dict['cpu_times']))
|
||||
ctime = "%s:%s.%s" % (ctime.seconds // 60 % 60,
|
||||
str((ctime.seconds % 60)).zfill(2),
|
||||
str(ctime.microseconds)[:2])
|
||||
else:
|
||||
ctime = ''
|
||||
if p.dict['memory_percent'] is not None:
|
||||
p.dict['memory_percent'] = round(p.dict['memory_percent'], 1)
|
||||
else:
|
||||
p.dict['memory_percent'] = ''
|
||||
if p.dict['cpu_percent'] is None:
|
||||
p.dict['cpu_percent'] = ''
|
||||
if p.dict['username']:
|
||||
username = p.dict['username'][:8]
|
||||
else:
|
||||
username = ""
|
||||
line = templ % (p.pid,
|
||||
username,
|
||||
p.dict['nice'],
|
||||
bytes2human(getattr(p.dict['memory_info'], 'vms', 0)),
|
||||
bytes2human(getattr(p.dict['memory_info'], 'rss', 0)),
|
||||
p.dict['cpu_percent'],
|
||||
p.dict['memory_percent'],
|
||||
ctime,
|
||||
p.dict['name'] or '',
|
||||
)
|
||||
try:
|
||||
print_line(line)
|
||||
except curses.error:
|
||||
break
|
||||
win.refresh()
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
interval = 0
|
||||
while True:
|
||||
args = poll(interval)
|
||||
refresh_window(*args)
|
||||
interval = 1
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
33
python/psutil/examples/who.py
Normal file
33
python/psutil/examples/who.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A clone of 'who' command; print information about users who are
|
||||
currently logged in.
|
||||
|
||||
$ python examples/who.py
|
||||
giampaolo tty7 2014-02-23 17:25 (:0)
|
||||
giampaolo pts/7 2014-02-24 18:25 (:192.168.1.56)
|
||||
giampaolo pts/8 2014-02-24 18:25 (:0)
|
||||
giampaolo pts/9 2014-02-27 01:32 (:0)
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
def main():
|
||||
users = psutil.users()
|
||||
for user in users:
|
||||
print("%-15s %-15s %s (%s)" % (
|
||||
user.name,
|
||||
user.terminal or '-',
|
||||
datetime.fromtimestamp(user.started).strftime("%Y-%m-%d %H:%M"),
|
||||
user.host))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
201
python/psutil/make.bat
Normal file
201
python/psutil/make.bat
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
@echo off
|
||||
|
||||
rem ==========================================================================
|
||||
rem Shortcuts for various tasks, emulating UNIX "make" on Windows.
|
||||
rem It is primarly intended as a shortcut for compiling / installing
|
||||
rem psutil ("make.bat build", "make.bat install") and running tests
|
||||
rem ("make.bat test").
|
||||
rem
|
||||
rem This script is modeled after my Windows installation which uses:
|
||||
rem - Visual studio 2008 for Python 2.6, 2.7, 3.2
|
||||
rem - Visual studio 2010 for Python 3.3+
|
||||
rem ...therefore it might not work on your Windows installation.
|
||||
rem
|
||||
rem By default C:\Python27\python.exe is used.
|
||||
rem To compile for a specific Python version run:
|
||||
rem set PYTHON=C:\Python34\python.exe & make.bat build
|
||||
rem
|
||||
rem To use a different test script:
|
||||
rem set PYTHON=C:\Python34\python.exe & set TSCRIPT=foo.py & make.bat test
|
||||
rem ==========================================================================
|
||||
|
||||
if "%PYTHON%" == "" (
|
||||
set PYTHON=C:\Python27\python.exe
|
||||
)
|
||||
if "%TSCRIPT%" == "" (
|
||||
set TSCRIPT=test\test_psutil.py
|
||||
)
|
||||
|
||||
set PYTHON26=C:\Python26\python.exe
|
||||
set PYTHON27=C:\Python27\python.exe
|
||||
set PYTHON33=C:\Python33\python.exe
|
||||
set PYTHON34=C:\Python34\python.exe
|
||||
set PYTHON26-64=C:\Python26-64\python.exe
|
||||
set PYTHON27-64=C:\Python27-64\python.exe
|
||||
set PYTHON33-64=C:\Python33-64\python.exe
|
||||
set PYTHON34-64=C:\Python34-64\python.exe
|
||||
|
||||
set ALL_PYTHONS=%PYTHON26% %PYTHON27% %PYTHON33% %PYTHON34% %PYTHON26-64% %PYTHON27-64% %PYTHON33-64% %PYTHON34-64%
|
||||
|
||||
rem Needed to locate the .pypirc file and upload exes on PYPI.
|
||||
set HOME=%USERPROFILE%
|
||||
|
||||
rem ==========================================================================
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo Run `make ^<target^>` where ^<target^> is one of:
|
||||
echo build compile without installing
|
||||
echo build-all build exes + wheels
|
||||
echo clean clean build files
|
||||
echo flake8 run flake8
|
||||
echo install compile and install
|
||||
echo setup-dev-env install pip, pywin32, wheels, etc. for all python versions
|
||||
echo test run tests
|
||||
echo test-memleaks run memory leak tests
|
||||
echo test-process run process related tests
|
||||
echo test-system run system APIs related tests
|
||||
echo uninstall uninstall
|
||||
echo upload-all upload exes + wheels
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /r %%R in (__pycache__) do if exist %%R (rmdir /S /Q %%R)
|
||||
for /r %%R in (*.pyc) do if exist %%R (del /s %%R)
|
||||
for /r %%R in (*.pyd) do if exist %%R (del /s %%R)
|
||||
for /r %%R in (*.orig) do if exist %%R (del /s %%R)
|
||||
for /r %%R in (*.bak) do if exist %%R (del /s %%R)
|
||||
for /r %%R in (*.rej) do if exist %%R (del /s %%R)
|
||||
if exist psutil.egg-info (rmdir /S /Q psutil.egg-info)
|
||||
if exist build (rmdir /S /Q build)
|
||||
if exist dist (rmdir /S /Q dist)
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "build" (
|
||||
:build
|
||||
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
|
||||
%PYTHON% setup.py build
|
||||
if %errorlevel% neq 0 goto :error
|
||||
rem copies *.pyd files in ./psutil directory in order to allow
|
||||
rem "import psutil" when using the interactive interpreter from
|
||||
rem within this directory.
|
||||
%PYTHON% setup.py build_ext -i
|
||||
if %errorlevel% neq 0 goto :error
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "install" (
|
||||
:install
|
||||
call :build
|
||||
%PYTHON% setup.py install
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "uninstall" (
|
||||
for %%A in ("%PYTHON%") do (
|
||||
set folder=%%~dpA
|
||||
)
|
||||
for /F "delims=" %%i in ('dir /b %folder%\Lib\site-packages\*psutil*') do (
|
||||
rmdir /S /Q %folder%\Lib\site-packages\%%i
|
||||
)
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "test" (
|
||||
call :install
|
||||
%PYTHON% %TSCRIPT%
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "test-process" (
|
||||
call :install
|
||||
%PYTHON% -m unittest -v test.test_psutil.TestProcess
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "test-system" (
|
||||
call :install
|
||||
%PYTHON% -m unittest -v test.test_psutil.TestSystem
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "test-memleaks" (
|
||||
call :install
|
||||
%PYTHON% test\test_memory_leaks.py
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "build-all" (
|
||||
:build-all
|
||||
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
|
||||
for %%P in (%ALL_PYTHONS%) do (
|
||||
@echo ------------------------------------------------
|
||||
@echo building exe for %%P
|
||||
@echo ------------------------------------------------
|
||||
%%P setup.py build bdist_wininst || goto :error
|
||||
@echo ------------------------------------------------
|
||||
@echo building wheel for %%P
|
||||
@echo ------------------------------------------------
|
||||
%%P setup.py build bdist_wheel || goto :error
|
||||
)
|
||||
echo OK
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "upload-all" (
|
||||
:upload-exes
|
||||
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
|
||||
for %%P in (%ALL_PYTHONS%) do (
|
||||
@echo ------------------------------------------------
|
||||
@echo uploading exe for %%P
|
||||
@echo ------------------------------------------------
|
||||
%%P setup.py build bdist_wininst upload || goto :error
|
||||
@echo ------------------------------------------------
|
||||
@echo uploading wheel for %%P
|
||||
@echo ------------------------------------------------
|
||||
%%P setup.py build bdist_wheel upload || goto :error
|
||||
)
|
||||
echo OK
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "setup-dev-env" (
|
||||
:setup-env
|
||||
@echo ------------------------------------------------
|
||||
@echo downloading pip installer
|
||||
@echo ------------------------------------------------
|
||||
C:\python27\python.exe -c "import urllib2; r = urllib2.urlopen('https://raw.github.com/pypa/pip/master/contrib/get-pip.py'); open('get-pip.py', 'wb').write(r.read())"
|
||||
for %%P in (%ALL_PYTHONS%) do (
|
||||
@echo ------------------------------------------------
|
||||
@echo installing pip for %%P
|
||||
@echo ------------------------------------------------
|
||||
%%P get-pip.py
|
||||
)
|
||||
for %%P in (%ALL_PYTHONS%) do (
|
||||
@echo ------------------------------------------------
|
||||
@echo installing deps for %%P
|
||||
@echo ------------------------------------------------
|
||||
rem mandatory / for unittests
|
||||
%%P -m pip install unittest2 ipaddress mock wmi wheel pypiwin32 --upgrade
|
||||
rem nice to have
|
||||
%%P -m pip install ipdb pep8 pyflakes flake8 --upgrade
|
||||
)
|
||||
goto :eof
|
||||
)
|
||||
|
||||
if "%1" == "flake8" (
|
||||
:flake8
|
||||
%PYTHON% -c "from flake8.main import main; main()"
|
||||
goto :eof
|
||||
)
|
||||
|
||||
goto :help
|
||||
|
||||
:error
|
||||
@echo ------------------------------------------------
|
||||
@echo last command exited with error code %errorlevel%
|
||||
@echo ------------------------------------------------
|
||||
@exit /b %errorlevel%
|
||||
goto :eof
|
||||
1887
python/psutil/psutil/__init__.py
Normal file
1887
python/psutil/psutil/__init__.py
Normal file
File diff suppressed because it is too large
Load diff
246
python/psutil/psutil/_common.py
Normal file
246
python/psutil/psutil/_common.py
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
# /usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Common objects shared by all _ps* modules."""
|
||||
|
||||
from __future__ import division
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import socket
|
||||
import stat
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
|
||||
try:
|
||||
import threading
|
||||
except ImportError:
|
||||
import dummy_threading as threading
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
import enum
|
||||
else:
|
||||
enum = None
|
||||
|
||||
|
||||
# --- constants
|
||||
|
||||
AF_INET6 = getattr(socket, 'AF_INET6', None)
|
||||
AF_UNIX = getattr(socket, 'AF_UNIX', None)
|
||||
|
||||
STATUS_RUNNING = "running"
|
||||
STATUS_SLEEPING = "sleeping"
|
||||
STATUS_DISK_SLEEP = "disk-sleep"
|
||||
STATUS_STOPPED = "stopped"
|
||||
STATUS_TRACING_STOP = "tracing-stop"
|
||||
STATUS_ZOMBIE = "zombie"
|
||||
STATUS_DEAD = "dead"
|
||||
STATUS_WAKE_KILL = "wake-kill"
|
||||
STATUS_WAKING = "waking"
|
||||
STATUS_IDLE = "idle" # BSD
|
||||
STATUS_LOCKED = "locked" # BSD
|
||||
STATUS_WAITING = "waiting" # BSD
|
||||
|
||||
CONN_ESTABLISHED = "ESTABLISHED"
|
||||
CONN_SYN_SENT = "SYN_SENT"
|
||||
CONN_SYN_RECV = "SYN_RECV"
|
||||
CONN_FIN_WAIT1 = "FIN_WAIT1"
|
||||
CONN_FIN_WAIT2 = "FIN_WAIT2"
|
||||
CONN_TIME_WAIT = "TIME_WAIT"
|
||||
CONN_CLOSE = "CLOSE"
|
||||
CONN_CLOSE_WAIT = "CLOSE_WAIT"
|
||||
CONN_LAST_ACK = "LAST_ACK"
|
||||
CONN_LISTEN = "LISTEN"
|
||||
CONN_CLOSING = "CLOSING"
|
||||
CONN_NONE = "NONE"
|
||||
|
||||
if enum is None:
|
||||
NIC_DUPLEX_FULL = 2
|
||||
NIC_DUPLEX_HALF = 1
|
||||
NIC_DUPLEX_UNKNOWN = 0
|
||||
else:
|
||||
class NicDuplex(enum.IntEnum):
|
||||
NIC_DUPLEX_FULL = 2
|
||||
NIC_DUPLEX_HALF = 1
|
||||
NIC_DUPLEX_UNKNOWN = 0
|
||||
|
||||
globals().update(NicDuplex.__members__)
|
||||
|
||||
|
||||
# --- functions
|
||||
|
||||
def usage_percent(used, total, _round=None):
|
||||
"""Calculate percentage usage of 'used' against 'total'."""
|
||||
try:
|
||||
ret = (used / total) * 100
|
||||
except ZeroDivisionError:
|
||||
ret = 0
|
||||
if _round is not None:
|
||||
return round(ret, _round)
|
||||
else:
|
||||
return ret
|
||||
|
||||
|
||||
def memoize(fun):
|
||||
"""A simple memoize decorator for functions supporting (hashable)
|
||||
positional arguments.
|
||||
It also provides a cache_clear() function for clearing the cache:
|
||||
|
||||
>>> @memoize
|
||||
... def foo()
|
||||
... return 1
|
||||
...
|
||||
>>> foo()
|
||||
1
|
||||
>>> foo.cache_clear()
|
||||
>>>
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(*args, **kwargs):
|
||||
key = (args, frozenset(sorted(kwargs.items())))
|
||||
lock.acquire()
|
||||
try:
|
||||
try:
|
||||
return cache[key]
|
||||
except KeyError:
|
||||
ret = cache[key] = fun(*args, **kwargs)
|
||||
finally:
|
||||
lock.release()
|
||||
return ret
|
||||
|
||||
def cache_clear():
|
||||
"""Clear cache."""
|
||||
lock.acquire()
|
||||
try:
|
||||
cache.clear()
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
lock = threading.RLock()
|
||||
cache = {}
|
||||
wrapper.cache_clear = cache_clear
|
||||
return wrapper
|
||||
|
||||
|
||||
def isfile_strict(path):
|
||||
"""Same as os.path.isfile() but does not swallow EACCES / EPERM
|
||||
exceptions, see:
|
||||
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
|
||||
"""
|
||||
try:
|
||||
st = os.stat(path)
|
||||
except OSError as err:
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise
|
||||
return False
|
||||
else:
|
||||
return stat.S_ISREG(st.st_mode)
|
||||
|
||||
|
||||
def sockfam_to_enum(num):
|
||||
"""Convert a numeric socket family value to an IntEnum member.
|
||||
If it's not a known member, return the numeric value itself.
|
||||
"""
|
||||
if enum is None:
|
||||
return num
|
||||
try:
|
||||
return socket.AddressFamily(num)
|
||||
except (ValueError, AttributeError):
|
||||
return num
|
||||
|
||||
|
||||
def socktype_to_enum(num):
|
||||
"""Convert a numeric socket type value to an IntEnum member.
|
||||
If it's not a known member, return the numeric value itself.
|
||||
"""
|
||||
if enum is None:
|
||||
return num
|
||||
try:
|
||||
return socket.AddressType(num)
|
||||
except (ValueError, AttributeError):
|
||||
return num
|
||||
|
||||
|
||||
# --- Process.connections() 'kind' parameter mapping
|
||||
|
||||
conn_tmap = {
|
||||
"all": ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"tcp": ([AF_INET, AF_INET6], [SOCK_STREAM]),
|
||||
"tcp4": ([AF_INET], [SOCK_STREAM]),
|
||||
"udp": ([AF_INET, AF_INET6], [SOCK_DGRAM]),
|
||||
"udp4": ([AF_INET], [SOCK_DGRAM]),
|
||||
"inet": ([AF_INET, AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"inet4": ([AF_INET], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"inet6": ([AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
}
|
||||
|
||||
if AF_INET6 is not None:
|
||||
conn_tmap.update({
|
||||
"tcp6": ([AF_INET6], [SOCK_STREAM]),
|
||||
"udp6": ([AF_INET6], [SOCK_DGRAM]),
|
||||
})
|
||||
|
||||
if AF_UNIX is not None:
|
||||
conn_tmap.update({
|
||||
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
})
|
||||
|
||||
del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM
|
||||
|
||||
|
||||
# --- namedtuples for psutil.* system-related functions
|
||||
|
||||
# psutil.swap_memory()
|
||||
sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin',
|
||||
'sout'])
|
||||
# psutil.disk_usage()
|
||||
sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent'])
|
||||
# psutil.disk_io_counters()
|
||||
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes',
|
||||
'read_time', 'write_time'])
|
||||
# psutil.disk_partitions()
|
||||
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
|
||||
# psutil.net_io_counters()
|
||||
snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
|
||||
'packets_sent', 'packets_recv',
|
||||
'errin', 'errout',
|
||||
'dropin', 'dropout'])
|
||||
# psutil.users()
|
||||
suser = namedtuple('suser', ['name', 'terminal', 'host', 'started'])
|
||||
# psutil.net_connections()
|
||||
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||
'status', 'pid'])
|
||||
# psutil.net_if_addrs()
|
||||
snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast'])
|
||||
# psutil.net_if_stats()
|
||||
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
|
||||
|
||||
|
||||
# --- namedtuples for psutil.Process methods
|
||||
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms'])
|
||||
# psutil.Process.cpu_times()
|
||||
pcputimes = namedtuple('pcputimes', ['user', 'system'])
|
||||
# psutil.Process.open_files()
|
||||
popenfile = namedtuple('popenfile', ['path', 'fd'])
|
||||
# psutil.Process.threads()
|
||||
pthread = namedtuple('pthread', ['id', 'user_time', 'system_time'])
|
||||
# psutil.Process.uids()
|
||||
puids = namedtuple('puids', ['real', 'effective', 'saved'])
|
||||
# psutil.Process.gids()
|
||||
pgids = namedtuple('pgids', ['real', 'effective', 'saved'])
|
||||
# psutil.Process.io_counters()
|
||||
pio = namedtuple('pio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes'])
|
||||
# psutil.Process.ionice()
|
||||
pionice = namedtuple('pionice', ['ioclass', 'value'])
|
||||
# psutil.Process.ctx_switches()
|
||||
pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary'])
|
||||
# psutil.Process.connections()
|
||||
pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||
'status'])
|
||||
189
python/psutil/psutil/_compat.py
Normal file
189
python/psutil/psutil/_compat.py
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Module which provides compatibility with older Python versions."""
|
||||
|
||||
import collections
|
||||
import functools
|
||||
import sys
|
||||
|
||||
__all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"]
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
long = int
|
||||
xrange = range
|
||||
unicode = str
|
||||
|
||||
def u(s):
|
||||
return s
|
||||
else:
|
||||
long = long
|
||||
xrange = xrange
|
||||
unicode = unicode
|
||||
|
||||
def u(s):
|
||||
return unicode(s, "unicode_escape")
|
||||
|
||||
|
||||
# removed in 3.0, reintroduced in 3.2
|
||||
try:
|
||||
callable = callable
|
||||
except NameError:
|
||||
def callable(obj):
|
||||
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
||||
|
||||
|
||||
# --- stdlib additions
|
||||
|
||||
|
||||
# py 3.2 functools.lru_cache
|
||||
# Taken from: http://code.activestate.com/recipes/578078
|
||||
# Credit: Raymond Hettinger
|
||||
try:
|
||||
from functools import lru_cache
|
||||
except ImportError:
|
||||
try:
|
||||
from threading import RLock
|
||||
except ImportError:
|
||||
from dummy_threading import RLock
|
||||
|
||||
_CacheInfo = collections.namedtuple(
|
||||
"CacheInfo", ["hits", "misses", "maxsize", "currsize"])
|
||||
|
||||
class _HashedSeq(list):
|
||||
__slots__ = 'hashvalue'
|
||||
|
||||
def __init__(self, tup, hash=hash):
|
||||
self[:] = tup
|
||||
self.hashvalue = hash(tup)
|
||||
|
||||
def __hash__(self):
|
||||
return self.hashvalue
|
||||
|
||||
def _make_key(args, kwds, typed,
|
||||
kwd_mark=(object(), ),
|
||||
fasttypes=set((int, str, frozenset, type(None))),
|
||||
sorted=sorted, tuple=tuple, type=type, len=len):
|
||||
key = args
|
||||
if kwds:
|
||||
sorted_items = sorted(kwds.items())
|
||||
key += kwd_mark
|
||||
for item in sorted_items:
|
||||
key += item
|
||||
if typed:
|
||||
key += tuple(type(v) for v in args)
|
||||
if kwds:
|
||||
key += tuple(type(v) for k, v in sorted_items)
|
||||
elif len(key) == 1 and type(key[0]) in fasttypes:
|
||||
return key[0]
|
||||
return _HashedSeq(key)
|
||||
|
||||
def lru_cache(maxsize=100, typed=False):
|
||||
"""Least-recently-used cache decorator, see:
|
||||
http://docs.python.org/3/library/functools.html#functools.lru_cache
|
||||
"""
|
||||
def decorating_function(user_function):
|
||||
cache = dict()
|
||||
stats = [0, 0]
|
||||
HITS, MISSES = 0, 1
|
||||
make_key = _make_key
|
||||
cache_get = cache.get
|
||||
_len = len
|
||||
lock = RLock()
|
||||
root = []
|
||||
root[:] = [root, root, None, None]
|
||||
nonlocal_root = [root]
|
||||
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3
|
||||
if maxsize == 0:
|
||||
def wrapper(*args, **kwds):
|
||||
result = user_function(*args, **kwds)
|
||||
stats[MISSES] += 1
|
||||
return result
|
||||
elif maxsize is None:
|
||||
def wrapper(*args, **kwds):
|
||||
key = make_key(args, kwds, typed)
|
||||
result = cache_get(key, root)
|
||||
if result is not root:
|
||||
stats[HITS] += 1
|
||||
return result
|
||||
result = user_function(*args, **kwds)
|
||||
cache[key] = result
|
||||
stats[MISSES] += 1
|
||||
return result
|
||||
else:
|
||||
def wrapper(*args, **kwds):
|
||||
if kwds or typed:
|
||||
key = make_key(args, kwds, typed)
|
||||
else:
|
||||
key = args
|
||||
lock.acquire()
|
||||
try:
|
||||
link = cache_get(key)
|
||||
if link is not None:
|
||||
root, = nonlocal_root
|
||||
link_prev, link_next, key, result = link
|
||||
link_prev[NEXT] = link_next
|
||||
link_next[PREV] = link_prev
|
||||
last = root[PREV]
|
||||
last[NEXT] = root[PREV] = link
|
||||
link[PREV] = last
|
||||
link[NEXT] = root
|
||||
stats[HITS] += 1
|
||||
return result
|
||||
finally:
|
||||
lock.release()
|
||||
result = user_function(*args, **kwds)
|
||||
lock.acquire()
|
||||
try:
|
||||
root, = nonlocal_root
|
||||
if key in cache:
|
||||
pass
|
||||
elif _len(cache) >= maxsize:
|
||||
oldroot = root
|
||||
oldroot[KEY] = key
|
||||
oldroot[RESULT] = result
|
||||
root = nonlocal_root[0] = oldroot[NEXT]
|
||||
oldkey = root[KEY]
|
||||
root[KEY] = root[RESULT] = None
|
||||
del cache[oldkey]
|
||||
cache[key] = oldroot
|
||||
else:
|
||||
last = root[PREV]
|
||||
link = [last, root, key, result]
|
||||
last[NEXT] = root[PREV] = cache[key] = link
|
||||
stats[MISSES] += 1
|
||||
finally:
|
||||
lock.release()
|
||||
return result
|
||||
|
||||
def cache_info():
|
||||
"""Report cache statistics"""
|
||||
lock.acquire()
|
||||
try:
|
||||
return _CacheInfo(stats[HITS], stats[MISSES], maxsize,
|
||||
len(cache))
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
def cache_clear():
|
||||
"""Clear the cache and cache statistics"""
|
||||
lock.acquire()
|
||||
try:
|
||||
cache.clear()
|
||||
root = nonlocal_root[0]
|
||||
root[:] = [root, root, None, None]
|
||||
stats[:] = [0, 0]
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
wrapper.__wrapped__ = user_function
|
||||
wrapper.cache_info = cache_info
|
||||
wrapper.cache_clear = cache_clear
|
||||
return functools.update_wrapper(wrapper, user_function)
|
||||
|
||||
return decorating_function
|
||||
455
python/psutil/psutil/_psbsd.py
Normal file
455
python/psutil/psutil/_psbsd.py
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""FreeBSD platform implementation."""
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_bsd as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import conn_tmap, usage_percent, sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
||||
# --- constants
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SWAIT: _common.STATUS_WAITING,
|
||||
cext.SLOCK: _common.STATUS_LOCKED,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
}
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
# extend base mem ntuple with BSD-specific memory metrics
|
||||
svmem = namedtuple(
|
||||
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
||||
'active', 'inactive', 'buffers', 'cached', 'shared', 'wired'])
|
||||
scputimes = namedtuple(
|
||||
'scputimes', ['user', 'nice', 'system', 'idle', 'irq'])
|
||||
pextmem = namedtuple('pextmem', ['rss', 'vms', 'text', 'data', 'stack'])
|
||||
pmmap_grouped = namedtuple(
|
||||
'pmmap_grouped', 'path rss, private, ref_count, shadow_count')
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count')
|
||||
|
||||
# set later from __init__.py
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
"""System virtual memory as a namedtuple."""
|
||||
mem = cext.virtual_mem()
|
||||
total, free, active, inactive, wired, cached, buffers, shared = mem
|
||||
avail = inactive + cached + free
|
||||
used = active + wired + cached
|
||||
percent = usage_percent((total - avail), total, _round=1)
|
||||
return svmem(total, avail, percent, used, free,
|
||||
active, inactive, buffers, cached, shared, wired)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""System swap memory as (total, used, free, sin, sout) namedtuple."""
|
||||
total, used, free, sin, sout = [x * PAGESIZE for x in cext.swap_mem()]
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system per-CPU times as a namedtuple"""
|
||||
user, nice, system, idle, irq = cext.cpu_times()
|
||||
return scputimes(user, nice, system, idle, irq)
|
||||
|
||||
|
||||
if hasattr(cext, "per_cpu_times"):
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a namedtuple"""
|
||||
ret = []
|
||||
for cpu_t in cext.per_cpu_times():
|
||||
user, nice, system, idle, irq = cpu_t
|
||||
item = scputimes(user, nice, system, idle, irq)
|
||||
ret.append(item)
|
||||
return ret
|
||||
else:
|
||||
# XXX
|
||||
# Ok, this is very dirty.
|
||||
# On FreeBSD < 8 we cannot gather per-cpu information, see:
|
||||
# https://github.com/giampaolo/psutil/issues/226
|
||||
# If num cpus > 1, on first call we return single cpu times to avoid a
|
||||
# crash at psutil import time.
|
||||
# Next calls will fail with NotImplementedError
|
||||
def per_cpu_times():
|
||||
if cpu_count_logical() == 1:
|
||||
return [cpu_times()]
|
||||
if per_cpu_times.__called__:
|
||||
raise NotImplementedError("supported only starting from FreeBSD 8")
|
||||
per_cpu_times.__called__ = True
|
||||
return [cpu_times()]
|
||||
|
||||
per_cpu_times.__called__ = False
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
return cext.cpu_count_logical()
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
# From the C module we'll get an XML string similar to this:
|
||||
# http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
|
||||
# We may get None in case "sysctl kern.sched.topology_spec"
|
||||
# is not supported on this BSD version, in which case we'll mimic
|
||||
# os.cpu_count() and return None.
|
||||
ret = None
|
||||
s = cext.cpu_count_phys()
|
||||
if s is not None:
|
||||
# get rid of padding chars appended at the end of the string
|
||||
index = s.rfind("</groups>")
|
||||
if index != -1:
|
||||
s = s[:index + 9]
|
||||
root = ET.fromstring(s)
|
||||
try:
|
||||
ret = len(root.findall('group/children/group/cpu')) or None
|
||||
finally:
|
||||
# needed otherwise it will memleak
|
||||
root.clear()
|
||||
if not ret:
|
||||
# If logical CPUs are 1 it's obvious we'll have only 1
|
||||
# physical CPU.
|
||||
if cpu_count_logical() == 1:
|
||||
return 1
|
||||
return ret
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
if not os.path.isabs(device) or not os.path.exists(device):
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
def users():
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp = item
|
||||
if tty == '~':
|
||||
continue # reboot or shutdown
|
||||
nt = _common.suser(user, tty or None, hostname, tstamp)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
def net_connections(kind):
|
||||
if kind not in _common.conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
families, types = conn_tmap[kind]
|
||||
ret = set()
|
||||
rawlist = cext.net_connections()
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status, pid = item
|
||||
# TODO: apply filter at C level
|
||||
if fam in families and type in types:
|
||||
try:
|
||||
status = TCP_STATUSES[status]
|
||||
except KeyError:
|
||||
# XXX: Not sure why this happens. I saw this occurring
|
||||
# with IPv6 sockets opened by 'vim'. Those sockets
|
||||
# have a very short lifetime so maybe the kernel
|
||||
# can't initialize their status?
|
||||
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
names = net_io_counters().keys()
|
||||
ret = {}
|
||||
for name in names:
|
||||
isup, duplex, speed, mtu = cext_posix.net_if_stats(name)
|
||||
if hasattr(_common, 'NicDuplex'):
|
||||
duplex = _common.NicDuplex(duplex)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
pids = cext.pids
|
||||
pid_exists = _psposix.pid_exists
|
||||
disk_usage = _psposix.disk_usage
|
||||
net_io_counters = cext.net_io_counters
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Decorator which translates bare OSError exceptions into
|
||||
NoSuchProcess and AccessDenied.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
# support for private module import
|
||||
if (NoSuchProcess is None or AccessDenied is None or
|
||||
ZombieProcess is None):
|
||||
raise
|
||||
if err.errno == errno.ESRCH:
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
return cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
return cext.proc_exe(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
return cext.proc_cmdline(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
tty_nr = cext.proc_tty_nr(self.pid)
|
||||
tmap = _psposix._get_terminal_map()
|
||||
try:
|
||||
return tmap[tty_nr]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
return cext.proc_ppid(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
real, effective, saved = cext.proc_uids(self.pid)
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
real, effective, saved = cext.proc_gids(self.pid)
|
||||
return _common.pgids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
user, system = cext.proc_cpu_times(self.pid)
|
||||
return _common.pcputimes(user, system)
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
rss, vms = cext.proc_memory_info(self.pid)[:2]
|
||||
return _common.pmem(rss, vms)
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info_ex(self):
|
||||
return pextmem(*cext.proc_memory_info(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return cext.proc_create_time(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return cext.proc_num_threads(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
return _common.pctxsw(*cext.proc_num_ctx_switches(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
if kind not in conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
families, types = conn_tmap[kind]
|
||||
rawlist = cext.proc_connections(self.pid, families, types)
|
||||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
status = TCP_STATUSES[status]
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
ret.append(nt)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
try:
|
||||
return _psposix.wait_pid(self.pid, timeout)
|
||||
except _psposix.TimeoutExpired:
|
||||
# support for private module import
|
||||
if TimeoutExpired is None:
|
||||
raise
|
||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
return cext_posix.getpriority(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = cext.proc_status(self.pid)
|
||||
if code in PROC_STATUSES:
|
||||
return PROC_STATUSES[code]
|
||||
# XXX is this legit? will we even ever get here?
|
||||
return "?"
|
||||
|
||||
@wrap_exceptions
|
||||
def io_counters(self):
|
||||
rc, wc, rb, wb = cext.proc_io_counters(self.pid)
|
||||
return _common.pio(rc, wc, rb, wb)
|
||||
|
||||
nt_mmap_grouped = namedtuple(
|
||||
'mmap', 'path rss, private, ref_count, shadow_count')
|
||||
nt_mmap_ext = namedtuple(
|
||||
'mmap', 'addr, perms path rss, private, ref_count, shadow_count')
|
||||
|
||||
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||
# and kinfo_getvmmap()
|
||||
if hasattr(cext, 'proc_open_files'):
|
||||
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
"""Return files opened by process as a list of namedtuples."""
|
||||
rawlist = cext.proc_open_files(self.pid)
|
||||
return [_common.popenfile(path, fd) for path, fd in rawlist]
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
"""Return process current working directory."""
|
||||
# sometimes we get an empty string, in which case we turn
|
||||
# it into None
|
||||
return cext.proc_cwd(self.pid) or None
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_maps(self):
|
||||
return cext.proc_memory_maps(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
"""Return the number of file descriptors opened by this process."""
|
||||
return cext.proc_num_fds(self.pid)
|
||||
|
||||
else:
|
||||
def _not_implemented(self):
|
||||
raise NotImplementedError("supported only starting from FreeBSD 8")
|
||||
|
||||
open_files = _not_implemented
|
||||
proc_cwd = _not_implemented
|
||||
memory_maps = _not_implemented
|
||||
num_fds = _not_implemented
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_affinity_get(self):
|
||||
return cext.proc_cpu_affinity_get(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_affinity_set(self, cpus):
|
||||
# Pre-emptively check if CPUs are valid because the C
|
||||
# function has a weird behavior in case of invalid CPUs,
|
||||
# see: https://github.com/giampaolo/psutil/issues/586
|
||||
allcpus = tuple(range(len(per_cpu_times())))
|
||||
for cpu in cpus:
|
||||
if cpu not in allcpus:
|
||||
raise ValueError("invalid CPU #%i (choose between %s)"
|
||||
% (cpu, allcpus))
|
||||
try:
|
||||
cext.proc_cpu_affinity_set(self.pid, cpus)
|
||||
except OSError as err:
|
||||
# 'man cpuset_setaffinity' about EDEADLK:
|
||||
# <<the call would leave a thread without a valid CPU to run
|
||||
# on because the set does not overlap with the thread's
|
||||
# anonymous mask>>
|
||||
if err.errno in (errno.EINVAL, errno.EDEADLK):
|
||||
for cpu in cpus:
|
||||
if cpu not in allcpus:
|
||||
raise ValueError("invalid CPU #%i (choose between %s)"
|
||||
% (cpu, allcpus))
|
||||
raise
|
||||
1206
python/psutil/psutil/_pslinux.py
Normal file
1206
python/psutil/psutil/_pslinux.py
Normal file
File diff suppressed because it is too large
Load diff
363
python/psutil/psutil/_psosx.py
Normal file
363
python/psutil/psutil/_psosx.py
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""OSX platform implementation."""
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_osx as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import conn_tmap, usage_percent, isfile_strict
|
||||
from ._common import sockfam_to_enum, socktype_to_enum
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
||||
# --- constants
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
# http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
}
|
||||
|
||||
scputimes = namedtuple('scputimes', ['user', 'nice', 'system', 'idle'])
|
||||
|
||||
svmem = namedtuple(
|
||||
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
||||
'active', 'inactive', 'wired'])
|
||||
|
||||
pextmem = namedtuple('pextmem', ['rss', 'vms', 'pfaults', 'pageins'])
|
||||
|
||||
pmmap_grouped = namedtuple(
|
||||
'pmmap_grouped',
|
||||
'path rss private swapped dirtied ref_count shadow_depth')
|
||||
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||
|
||||
# set later from __init__.py
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
# --- functions
|
||||
|
||||
def virtual_memory():
|
||||
"""System virtual memory as a namedtuple."""
|
||||
total, active, inactive, wired, free = cext.virtual_mem()
|
||||
avail = inactive + free
|
||||
used = active + inactive + wired
|
||||
percent = usage_percent((total - avail), total, _round=1)
|
||||
return svmem(total, avail, percent, used, free,
|
||||
active, inactive, wired)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
|
||||
total, used, free, sin, sout = cext.swap_mem()
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system CPU times as a namedtuple."""
|
||||
user, nice, system, idle = cext.cpu_times()
|
||||
return scputimes(user, nice, system, idle)
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a named tuple"""
|
||||
ret = []
|
||||
for cpu_t in cext.per_cpu_times():
|
||||
user, nice, system, idle = cpu_t
|
||||
item = scputimes(user, nice, system, idle)
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
return cext.cpu_count_logical()
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
return cext.cpu_count_phys()
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
if not os.path.isabs(device) or not os.path.exists(device):
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
def users():
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp = item
|
||||
if tty == '~':
|
||||
continue # reboot or shutdown
|
||||
if not tstamp:
|
||||
continue
|
||||
nt = _common.suser(user, tty or None, hostname or None, tstamp)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
def net_connections(kind='inet'):
|
||||
# Note: on OSX this will fail with AccessDenied unless
|
||||
# the process is owned by root.
|
||||
ret = []
|
||||
for pid in pids():
|
||||
try:
|
||||
cons = Process(pid).connections(kind)
|
||||
except NoSuchProcess:
|
||||
continue
|
||||
else:
|
||||
if cons:
|
||||
for c in cons:
|
||||
c = list(c) + [pid]
|
||||
ret.append(_common.sconn(*c))
|
||||
return ret
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
names = net_io_counters().keys()
|
||||
ret = {}
|
||||
for name in names:
|
||||
isup, duplex, speed, mtu = cext_posix.net_if_stats(name)
|
||||
if hasattr(_common, 'NicDuplex'):
|
||||
duplex = _common.NicDuplex(duplex)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
pids = cext.pids
|
||||
pid_exists = _psposix.pid_exists
|
||||
disk_usage = _psposix.disk_usage
|
||||
net_io_counters = cext.net_io_counters
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Decorator which translates bare OSError exceptions into
|
||||
NoSuchProcess and AccessDenied.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
# support for private module import
|
||||
if (NoSuchProcess is None or AccessDenied is None or
|
||||
ZombieProcess is None):
|
||||
raise
|
||||
if err.errno == errno.ESRCH:
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
return cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
return cext.proc_exe(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
return cext.proc_cmdline(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
return cext.proc_ppid(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
return cext.proc_cwd(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
real, effective, saved = cext.proc_uids(self.pid)
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
real, effective, saved = cext.proc_gids(self.pid)
|
||||
return _common.pgids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
tty_nr = cext.proc_tty_nr(self.pid)
|
||||
tmap = _psposix._get_terminal_map()
|
||||
try:
|
||||
return tmap[tty_nr]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
rss, vms = cext.proc_memory_info(self.pid)[:2]
|
||||
return _common.pmem(rss, vms)
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info_ex(self):
|
||||
rss, vms, pfaults, pageins = cext.proc_memory_info(self.pid)
|
||||
return pextmem(rss, vms, pfaults * PAGESIZE, pageins * PAGESIZE)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
user, system = cext.proc_cpu_times(self.pid)
|
||||
return _common.pcputimes(user, system)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return cext.proc_create_time(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
return _common.pctxsw(*cext.proc_num_ctx_switches(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return cext.proc_num_threads(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
if self.pid == 0:
|
||||
return []
|
||||
files = []
|
||||
rawlist = cext.proc_open_files(self.pid)
|
||||
for path, fd in rawlist:
|
||||
if isfile_strict(path):
|
||||
ntuple = _common.popenfile(path, fd)
|
||||
files.append(ntuple)
|
||||
return files
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
if kind not in conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
families, types = conn_tmap[kind]
|
||||
rawlist = cext.proc_connections(self.pid, families, types)
|
||||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
status = TCP_STATUSES[status]
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
ret.append(nt)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
if self.pid == 0:
|
||||
return 0
|
||||
return cext.proc_num_fds(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
try:
|
||||
return _psposix.wait_pid(self.pid, timeout)
|
||||
except _psposix.TimeoutExpired:
|
||||
# support for private module import
|
||||
if TimeoutExpired is None:
|
||||
raise
|
||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
return cext_posix.getpriority(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = cext.proc_status(self.pid)
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_maps(self):
|
||||
return cext.proc_memory_maps(self.pid)
|
||||
156
python/psutil/psutil/_psposix.py
Normal file
156
python/psutil/psutil/_psposix.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Routines common to all posix systems."""
|
||||
|
||||
import errno
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from ._common import sdiskusage, usage_percent, memoize
|
||||
from ._compat import PY3, unicode
|
||||
|
||||
|
||||
class TimeoutExpired(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check whether pid exists in the current process table."""
|
||||
if pid == 0:
|
||||
# According to "man 2 kill" PID 0 has a special meaning:
|
||||
# it refers to <<every process in the process group of the
|
||||
# calling process>> so we don't want to go any further.
|
||||
# If we get here it means this UNIX platform *does* have
|
||||
# a process with id 0.
|
||||
return True
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ESRCH:
|
||||
# ESRCH == No such process
|
||||
return False
|
||||
elif err.errno == errno.EPERM:
|
||||
# EPERM clearly means there's a process to deny access to
|
||||
return True
|
||||
else:
|
||||
# According to "man 2 kill" possible error values are
|
||||
# (EINVAL, EPERM, ESRCH) therefore we should never get
|
||||
# here. If we do let's be explicit in considering this
|
||||
# an error.
|
||||
raise err
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def wait_pid(pid, timeout=None):
|
||||
"""Wait for process with pid 'pid' to terminate and return its
|
||||
exit status code as an integer.
|
||||
|
||||
If pid is not a children of os.getpid() (current process) just
|
||||
waits until the process disappears and return None.
|
||||
|
||||
If pid does not exist at all return None immediately.
|
||||
|
||||
Raise TimeoutExpired on timeout expired.
|
||||
"""
|
||||
def check_timeout(delay):
|
||||
if timeout is not None:
|
||||
if timer() >= stop_at:
|
||||
raise TimeoutExpired()
|
||||
time.sleep(delay)
|
||||
return min(delay * 2, 0.04)
|
||||
|
||||
timer = getattr(time, 'monotonic', time.time)
|
||||
if timeout is not None:
|
||||
def waitcall():
|
||||
return os.waitpid(pid, os.WNOHANG)
|
||||
stop_at = timer() + timeout
|
||||
else:
|
||||
def waitcall():
|
||||
return os.waitpid(pid, 0)
|
||||
|
||||
delay = 0.0001
|
||||
while True:
|
||||
try:
|
||||
retpid, status = waitcall()
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINTR:
|
||||
delay = check_timeout(delay)
|
||||
continue
|
||||
elif err.errno == errno.ECHILD:
|
||||
# This has two meanings:
|
||||
# - pid is not a child of os.getpid() in which case
|
||||
# we keep polling until it's gone
|
||||
# - pid never existed in the first place
|
||||
# In both cases we'll eventually return None as we
|
||||
# can't determine its exit status code.
|
||||
while True:
|
||||
if pid_exists(pid):
|
||||
delay = check_timeout(delay)
|
||||
else:
|
||||
return
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
if retpid == 0:
|
||||
# WNOHANG was used, pid is still running
|
||||
delay = check_timeout(delay)
|
||||
continue
|
||||
# process exited due to a signal; return the integer of
|
||||
# that signal
|
||||
if os.WIFSIGNALED(status):
|
||||
return os.WTERMSIG(status)
|
||||
# process exited using exit(2) system call; return the
|
||||
# integer exit(2) system call has been called with
|
||||
elif os.WIFEXITED(status):
|
||||
return os.WEXITSTATUS(status)
|
||||
else:
|
||||
# should never happen
|
||||
raise RuntimeError("unknown process exit status")
|
||||
|
||||
|
||||
def disk_usage(path):
|
||||
"""Return disk usage associated with path."""
|
||||
try:
|
||||
st = os.statvfs(path)
|
||||
except UnicodeEncodeError:
|
||||
if not PY3 and isinstance(path, unicode):
|
||||
# this is a bug with os.statvfs() and unicode on
|
||||
# Python 2, see:
|
||||
# - https://github.com/giampaolo/psutil/issues/416
|
||||
# - http://bugs.python.org/issue18695
|
||||
try:
|
||||
path = path.encode(sys.getfilesystemencoding())
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
st = os.statvfs(path)
|
||||
else:
|
||||
raise
|
||||
free = (st.f_bavail * st.f_frsize)
|
||||
total = (st.f_blocks * st.f_frsize)
|
||||
used = (st.f_blocks - st.f_bfree) * st.f_frsize
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
# NB: the percentage is -5% than what shown by df due to
|
||||
# reserved blocks that we are currently not considering:
|
||||
# http://goo.gl/sWGbH
|
||||
return sdiskusage(total, used, free, percent)
|
||||
|
||||
|
||||
@memoize
|
||||
def _get_terminal_map():
|
||||
ret = {}
|
||||
ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*')
|
||||
for name in ls:
|
||||
assert name not in ret
|
||||
try:
|
||||
ret[os.stat(name).st_rdev] = name
|
||||
except OSError as err:
|
||||
if err.errno != errno.ENOENT:
|
||||
raise
|
||||
return ret
|
||||
553
python/psutil/psutil/_pssunos.py
Normal file
553
python/psutil/psutil/_pssunos.py
Normal file
|
|
@ -0,0 +1,553 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Sun OS Solaris platform implementation."""
|
||||
|
||||
import errno
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_posix as cext_posix
|
||||
from . import _psutil_sunos as cext
|
||||
from ._common import isfile_strict, socktype_to_enum, sockfam_to_enum
|
||||
from ._common import usage_percent
|
||||
from ._compat import PY3
|
||||
|
||||
|
||||
__extra__all__ = ["CONN_IDLE", "CONN_BOUND"]
|
||||
|
||||
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
CONN_IDLE = "IDLE"
|
||||
CONN_BOUND = "BOUND"
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SONPROC: _common.STATUS_RUNNING, # same as run
|
||||
cext.SWAIT: _common.STATUS_WAITING,
|
||||
}
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
cext.TCPS_IDLE: CONN_IDLE, # sunos specific
|
||||
cext.TCPS_BOUND: CONN_BOUND, # sunos specific
|
||||
}
|
||||
|
||||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||
pextmem = namedtuple('pextmem', ['rss', 'vms'])
|
||||
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss', 'anon', 'locked'])
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||
|
||||
# set later from __init__.py
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
# --- functions
|
||||
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
net_io_counters = cext.net_io_counters
|
||||
disk_usage = _psposix.disk_usage
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
# we could have done this with kstat, but imho this is good enough
|
||||
total = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE
|
||||
# note: there's no difference on Solaris
|
||||
free = avail = os.sysconf('SC_AVPHYS_PAGES') * PAGE_SIZE
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
return svmem(total, avail, percent, used, free)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
sin, sout = cext.swap_mem()
|
||||
# XXX
|
||||
# we are supposed to get total/free by doing so:
|
||||
# http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/
|
||||
# usr/src/cmd/swap/swap.c
|
||||
# ...nevertheless I can't manage to obtain the same numbers as 'swap'
|
||||
# cmdline utility, so let's parse its output (sigh!)
|
||||
p = subprocess.Popen(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' %
|
||||
os.environ['PATH'], 'swap', '-l', '-k'],
|
||||
stdout=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout = stdout.decode(sys.stdout.encoding)
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError("'swap -l -k' failed (retcode=%s)" % p.returncode)
|
||||
|
||||
lines = stdout.strip().split('\n')[1:]
|
||||
if not lines:
|
||||
raise RuntimeError('no swap device(s) configured')
|
||||
total = free = 0
|
||||
for line in lines:
|
||||
line = line.split()
|
||||
t, f = line[-2:]
|
||||
t = t.replace('K', '')
|
||||
f = f.replace('K', '')
|
||||
total += int(int(t) * 1024)
|
||||
free += int(int(f) * 1024)
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
return _common.sswap(total, used, free, percent,
|
||||
sin * PAGE_SIZE, sout * PAGE_SIZE)
|
||||
|
||||
|
||||
def pids():
|
||||
"""Returns a list of PIDs currently running on the system."""
|
||||
return [int(x) for x in os.listdir('/proc') if x.isdigit()]
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check for the existence of a unix pid."""
|
||||
return _psposix.pid_exists(pid)
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system-wide CPU times as a named tuple"""
|
||||
ret = cext.per_cpu_times()
|
||||
return scputimes(*[sum(x) for x in zip(*ret)])
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system per-CPU times as a list of named tuples"""
|
||||
ret = cext.per_cpu_times()
|
||||
return [scputimes(*x) for x in ret]
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
try:
|
||||
return os.sysconf("SC_NPROCESSORS_ONLN")
|
||||
except ValueError:
|
||||
# mimic os.cpu_count() behavior
|
||||
return None
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
return cext.cpu_count_phys()
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
localhost = (':0.0', ':0')
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, user_process = item
|
||||
# note: the underlying C function includes entries about
|
||||
# system boot, run level and others. We might want
|
||||
# to use them in the future.
|
||||
if not user_process:
|
||||
continue
|
||||
if hostname in localhost:
|
||||
hostname = 'localhost'
|
||||
nt = _common.suser(user, tty, hostname, tstamp)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return system disk partitions."""
|
||||
# TODO - the filtering logic should be better checked so that
|
||||
# it tries to reflect 'df' as much as possible
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
# Differently from, say, Linux, we don't have a list of
|
||||
# common fs types so the best we can do, AFAIK, is to
|
||||
# filter by filesystem having a total size > 0.
|
||||
if not disk_usage(mountpoint).total:
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
def net_connections(kind, _pid=-1):
|
||||
"""Return socket connections. If pid == -1 return system-wide
|
||||
connections (as opposed to connections opened by one process only).
|
||||
Only INET sockets are returned (UNIX are not).
|
||||
"""
|
||||
cmap = _common.conn_tmap.copy()
|
||||
if _pid == -1:
|
||||
cmap.pop('unix', 0)
|
||||
if kind not in cmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||
families, types = _common.conn_tmap[kind]
|
||||
rawlist = cext.net_connections(_pid, families, types)
|
||||
ret = set()
|
||||
for item in rawlist:
|
||||
fd, fam, type_, laddr, raddr, status, pid = item
|
||||
if fam not in families:
|
||||
continue
|
||||
if type_ not in types:
|
||||
continue
|
||||
status = TCP_STATUSES[status]
|
||||
fam = sockfam_to_enum(fam)
|
||||
type_ = socktype_to_enum(type_)
|
||||
if _pid == -1:
|
||||
nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid)
|
||||
else:
|
||||
nt = _common.pconn(fd, fam, type_, laddr, raddr, status)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
ret = cext.net_if_stats()
|
||||
for name, items in ret.items():
|
||||
isup, duplex, speed, mtu = items
|
||||
if hasattr(_common, 'NicDuplex'):
|
||||
duplex = _common.NicDuplex(duplex)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Call callable into a try/except clause and translate ENOENT,
|
||||
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
|
||||
"""
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except EnvironmentError as err:
|
||||
# support for private module import
|
||||
if (NoSuchProcess is None or AccessDenied is None or
|
||||
ZombieProcess is None):
|
||||
raise
|
||||
# ENOENT (no such file or directory) gets raised on open().
|
||||
# ESRCH (no such process) can get raised on read() if
|
||||
# process is gone in meantime.
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
# note: max len == 15
|
||||
return cext.proc_name_and_args(self.pid)[0]
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
# Will be guess later from cmdline but we want to explicitly
|
||||
# invoke cmdline here in order to get an AccessDenied
|
||||
# exception if the user has not enough privileges.
|
||||
self.cmdline()
|
||||
return ""
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
return cext.proc_name_and_args(self.pid)[1].split(' ')
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return cext.proc_basic_info(self.pid)[3]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return cext.proc_basic_info(self.pid)[5]
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
# For some reason getpriority(3) return ESRCH (no such process)
|
||||
# for certain low-pid processes, no matter what (even as root).
|
||||
# The process actually exists though, as it has a name,
|
||||
# creation time, etc.
|
||||
# The best thing we can do here appears to be raising AD.
|
||||
# Note: tested on Solaris 11; on Open Solaris 5 everything is
|
||||
# fine.
|
||||
try:
|
||||
return cext_posix.getpriority(self.pid)
|
||||
except EnvironmentError as err:
|
||||
# 48 is 'operation not supported' but errno does not expose
|
||||
# it. It occurs for low system pids.
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH, 48):
|
||||
if pid_exists(self.pid):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
if self.pid in (2, 3):
|
||||
# Special case PIDs: internally setpriority(3) return ESRCH
|
||||
# (no such process), no matter what.
|
||||
# The process actually exists though, as it has a name,
|
||||
# creation time, etc.
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
return cext.proc_basic_info(self.pid)[0]
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
real, effective, saved, _, _, _ = cext.proc_cred(self.pid)
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
_, _, _, real, effective, saved = cext.proc_cred(self.pid)
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
user, system = cext.proc_cpu_times(self.pid)
|
||||
return _common.pcputimes(user, system)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
hit_enoent = False
|
||||
tty = wrap_exceptions(
|
||||
cext.proc_basic_info(self.pid)[0])
|
||||
if tty != cext.PRNODEV:
|
||||
for x in (0, 1, 2, 255):
|
||||
try:
|
||||
return os.readlink('/proc/%d/path/%d' % (self.pid, x))
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
if hit_enoent:
|
||||
# raise NSP if the process disappeared on us
|
||||
os.stat('/proc/%s' % self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
# /proc/PID/path/cwd may not be resolved by readlink() even if
|
||||
# it exists (ls shows it). If that's the case and the process
|
||||
# is still alive return None (we can return None also on BSD).
|
||||
# Reference: http://goo.gl/55XgO
|
||||
try:
|
||||
return os.readlink("/proc/%s/path/cwd" % self.pid)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
os.stat("/proc/%s" % self.pid)
|
||||
return None
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
ret = cext.proc_basic_info(self.pid)
|
||||
rss, vms = ret[1] * 1024, ret[2] * 1024
|
||||
return _common.pmem(rss, vms)
|
||||
|
||||
# it seems Solaris uses rss and vms only
|
||||
memory_info_ex = memory_info
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = cext.proc_basic_info(self.pid)[6]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
ret = []
|
||||
tids = os.listdir('/proc/%d/lwp' % self.pid)
|
||||
hit_enoent = False
|
||||
for tid in tids:
|
||||
tid = int(tid)
|
||||
try:
|
||||
utime, stime = cext.query_process_thread(
|
||||
self.pid, tid)
|
||||
except EnvironmentError as err:
|
||||
# ENOENT == thread gone in meantime
|
||||
if err.errno == errno.ENOENT:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
nt = _common.pthread(tid, utime, stime)
|
||||
ret.append(nt)
|
||||
if hit_enoent:
|
||||
# raise NSP if the process disappeared on us
|
||||
os.stat('/proc/%s' % self.pid)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
retlist = []
|
||||
hit_enoent = False
|
||||
pathdir = '/proc/%d/path' % self.pid
|
||||
for fd in os.listdir('/proc/%d/fd' % self.pid):
|
||||
path = os.path.join(pathdir, fd)
|
||||
if os.path.islink(path):
|
||||
try:
|
||||
file = os.readlink(path)
|
||||
except OSError as err:
|
||||
# ENOENT == file which is gone in the meantime
|
||||
if err.errno == errno.ENOENT:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
if isfile_strict(file):
|
||||
retlist.append(_common.popenfile(file, int(fd)))
|
||||
if hit_enoent:
|
||||
# raise NSP if the process disappeared on us
|
||||
os.stat('/proc/%s' % self.pid)
|
||||
return retlist
|
||||
|
||||
def _get_unix_sockets(self, pid):
|
||||
"""Get UNIX sockets used by process by parsing 'pfiles' output."""
|
||||
# TODO: rewrite this in C (...but the damn netstat source code
|
||||
# does not include this part! Argh!!)
|
||||
cmd = "pfiles %s" % pid
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if p.returncode != 0:
|
||||
if 'permission denied' in stderr.lower():
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
if 'no such process' in stderr.lower():
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise RuntimeError("%r command error\n%s" % (cmd, stderr))
|
||||
|
||||
lines = stdout.split('\n')[2:]
|
||||
for i, line in enumerate(lines):
|
||||
line = line.lstrip()
|
||||
if line.startswith('sockname: AF_UNIX'):
|
||||
path = line.split(' ', 2)[2]
|
||||
type = lines[i - 2].strip()
|
||||
if type == 'SOCK_STREAM':
|
||||
type = socket.SOCK_STREAM
|
||||
elif type == 'SOCK_DGRAM':
|
||||
type = socket.SOCK_DGRAM
|
||||
else:
|
||||
type = -1
|
||||
yield (-1, socket.AF_UNIX, type, path, "", _common.CONN_NONE)
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
ret = net_connections(kind, _pid=self.pid)
|
||||
# The underlying C implementation retrieves all OS connections
|
||||
# and filters them by PID. At this point we can't tell whether
|
||||
# an empty list means there were no connections for process or
|
||||
# process is no longer active so we force NSP in case the PID
|
||||
# is no longer there.
|
||||
if not ret:
|
||||
os.stat('/proc/%s' % self.pid) # will raise NSP if process is gone
|
||||
|
||||
# UNIX sockets
|
||||
if kind in ('all', 'unix'):
|
||||
ret.extend([_common.pconn(*conn) for conn in
|
||||
self._get_unix_sockets(self.pid)])
|
||||
return ret
|
||||
|
||||
nt_mmap_grouped = namedtuple('mmap', 'path rss anon locked')
|
||||
nt_mmap_ext = namedtuple('mmap', 'addr perms path rss anon locked')
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_maps(self):
|
||||
def toaddr(start, end):
|
||||
return '%s-%s' % (hex(start)[2:].strip('L'),
|
||||
hex(end)[2:].strip('L'))
|
||||
|
||||
retlist = []
|
||||
rawlist = cext.proc_memory_maps(self.pid)
|
||||
hit_enoent = False
|
||||
for item in rawlist:
|
||||
addr, addrsize, perm, name, rss, anon, locked = item
|
||||
addr = toaddr(addr, addrsize)
|
||||
if not name.startswith('['):
|
||||
try:
|
||||
name = os.readlink('/proc/%s/path/%s' % (self.pid, name))
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
# sometimes the link may not be resolved by
|
||||
# readlink() even if it exists (ls shows it).
|
||||
# If that's the case we just return the
|
||||
# unresolved link path.
|
||||
# This seems an incosistency with /proc similar
|
||||
# to: http://goo.gl/55XgO
|
||||
name = '/proc/%s/path/%s' % (self.pid, name)
|
||||
hit_enoent = True
|
||||
else:
|
||||
raise
|
||||
retlist.append((addr, perm, name, rss, anon, locked))
|
||||
if hit_enoent:
|
||||
# raise NSP if the process disappeared on us
|
||||
os.stat('/proc/%s' % self.pid)
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
return len(os.listdir("/proc/%s/fd" % self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
return _common.pctxsw(*cext.proc_num_ctx_switches(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
try:
|
||||
return _psposix.wait_pid(self.pid, timeout)
|
||||
except _psposix.TimeoutExpired:
|
||||
# support for private module import
|
||||
if TimeoutExpired is None:
|
||||
raise
|
||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||
2296
python/psutil/psutil/_psutil_bsd.c
Normal file
2296
python/psutil/psutil/_psutil_bsd.c
Normal file
File diff suppressed because it is too large
Load diff
53
python/psutil/psutil/_psutil_bsd.h
Normal file
53
python/psutil/psutil/_psutil_bsd.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
// --- per-process functions
|
||||
|
||||
static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_connections(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_gids(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_name(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_ppid(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_status(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_uids(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
|
||||
static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
|
||||
#endif
|
||||
|
||||
// --- system-related functions
|
||||
|
||||
static PyObject* psutil_boot_time(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_pids(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
|
||||
static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
||||
#endif
|
||||
37
python/psutil/psutil/_psutil_common.c
Normal file
37
python/psutil/psutil/_psutil_common.c
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Routines common to all platforms.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
|
||||
/*
|
||||
* Set OSError(errno=ESRCH, strerror="No such process") Python exception.
|
||||
*/
|
||||
PyObject *
|
||||
NoSuchProcess(void) {
|
||||
PyObject *exc;
|
||||
char *msg = strerror(ESRCH);
|
||||
exc = PyObject_CallFunction(PyExc_OSError, "(is)", ESRCH, msg);
|
||||
PyErr_SetObject(PyExc_OSError, exc);
|
||||
Py_XDECREF(exc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set OSError(errno=EACCES, strerror="Permission denied") Python exception.
|
||||
*/
|
||||
PyObject *
|
||||
AccessDenied(void) {
|
||||
PyObject *exc;
|
||||
char *msg = strerror(EACCES);
|
||||
exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg);
|
||||
PyErr_SetObject(PyExc_OSError, exc);
|
||||
Py_XDECREF(exc);
|
||||
return NULL;
|
||||
}
|
||||
10
python/psutil/psutil/_psutil_common.h
Normal file
10
python/psutil/psutil/_psutil_common.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
PyObject* AccessDenied(void);
|
||||
PyObject* NoSuchProcess(void);
|
||||
689
python/psutil/psutil/_psutil_linux.c
Normal file
689
python/psutil/psutil/_psutil_linux.c
Normal file
|
|
@ -0,0 +1,689 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Linux-specific functions.
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
#include <Python.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <mntent.h>
|
||||
#include <features.h>
|
||||
#include <utmp.h>
|
||||
#include <sched.h>
|
||||
#include <linux/version.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include "_psutil_linux.h"
|
||||
|
||||
/* The minimum number of CPUs allocated in a cpu_set_t */
|
||||
static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
|
||||
|
||||
// Linux >= 2.6.13
|
||||
#define PSUTIL_HAVE_IOPRIO defined(__NR_ioprio_get) && defined(__NR_ioprio_set)
|
||||
|
||||
// Linux >= 2.6.36 (supposedly) and glibc >= 13
|
||||
#define PSUTIL_HAVE_PRLIMIT \
|
||||
(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) && \
|
||||
(__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 13) && \
|
||||
defined(__NR_prlimit64)
|
||||
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#include <time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if PSUTIL_HAVE_IOPRIO
|
||||
enum {
|
||||
IOPRIO_WHO_PROCESS = 1,
|
||||
};
|
||||
|
||||
// May happen on old RedHat versions, see:
|
||||
// https://github.com/giampaolo/psutil/issues/607
|
||||
#ifndef DUPLEX_UNKNOWN
|
||||
#define DUPLEX_UNKNOWN 0xff
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
ioprio_get(int which, int who)
|
||||
{
|
||||
return syscall(__NR_ioprio_get, which, who);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ioprio_set(int which, int who, int ioprio)
|
||||
{
|
||||
return syscall(__NR_ioprio_set, which, who, ioprio);
|
||||
}
|
||||
|
||||
#define IOPRIO_CLASS_SHIFT 13
|
||||
#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
|
||||
|
||||
#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
|
||||
#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
|
||||
#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
|
||||
|
||||
|
||||
/*
|
||||
* Return a (ioclass, iodata) Python tuple representing process I/O priority.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_proc_ioprio_get(PyObject *self, PyObject *args)
|
||||
{
|
||||
long pid;
|
||||
int ioprio, ioclass, iodata;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
return NULL;
|
||||
ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
|
||||
if (ioprio == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
ioclass = IOPRIO_PRIO_CLASS(ioprio);
|
||||
iodata = IOPRIO_PRIO_DATA(ioprio);
|
||||
return Py_BuildValue("ii", ioclass, iodata);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A wrapper around ioprio_set(); sets process I/O priority.
|
||||
* ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE
|
||||
* or 0. iodata goes from 0 to 7 depending on ioclass specified.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_proc_ioprio_set(PyObject *self, PyObject *args)
|
||||
{
|
||||
long pid;
|
||||
int ioprio, ioclass, iodata;
|
||||
int retval;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata))
|
||||
return NULL;
|
||||
ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
|
||||
retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
|
||||
if (retval == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
/*
|
||||
* A wrapper around prlimit(2); sets process resource limits.
|
||||
* This can be used for both get and set, in which case extra
|
||||
* 'soft' and 'hard' args must be provided.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_linux_prlimit(PyObject *self, PyObject *args)
|
||||
{
|
||||
long pid;
|
||||
int ret, resource;
|
||||
struct rlimit old, new;
|
||||
struct rlimit *newp = NULL;
|
||||
PyObject *soft = NULL;
|
||||
PyObject *hard = NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &soft, &hard))
|
||||
return NULL;
|
||||
|
||||
// get
|
||||
if (soft == NULL && hard == NULL) {
|
||||
ret = prlimit(pid, resource, NULL, &old);
|
||||
if (ret == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
#if defined(PSUTIL_HAVE_LONG_LONG)
|
||||
if (sizeof(old.rlim_cur) > sizeof(long)) {
|
||||
return Py_BuildValue("LL",
|
||||
(PY_LONG_LONG)old.rlim_cur,
|
||||
(PY_LONG_LONG)old.rlim_max);
|
||||
}
|
||||
#endif
|
||||
return Py_BuildValue("ll", (long)old.rlim_cur, (long)old.rlim_max);
|
||||
}
|
||||
|
||||
// set
|
||||
else {
|
||||
#if defined(PSUTIL_HAVE_LARGEFILE_SUPPORT)
|
||||
new.rlim_cur = PyLong_AsLongLong(soft);
|
||||
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
new.rlim_max = PyLong_AsLongLong(hard);
|
||||
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
#else
|
||||
new.rlim_cur = PyLong_AsLong(soft);
|
||||
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
new.rlim_max = PyLong_AsLong(hard);
|
||||
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
#endif
|
||||
newp = &new;
|
||||
ret = prlimit(pid, resource, newp, &old);
|
||||
if (ret == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Return disk mounted partitions as a list of tuples including device,
|
||||
* mount point and filesystem type
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_disk_partitions(PyObject *self, PyObject *args)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
struct mntent *entry;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
PyObject *py_tuple = NULL;
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
// MOUNTED constant comes from mntent.h and it's == '/etc/mtab'
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
file = setmntent(MOUNTED, "r");
|
||||
Py_END_ALLOW_THREADS
|
||||
if ((file == 0) || (file == NULL)) {
|
||||
PyErr_SetFromErrnoWithFilename(PyExc_OSError, MOUNTED);
|
||||
goto error;
|
||||
}
|
||||
|
||||
while ((entry = getmntent(file))) {
|
||||
if (entry == NULL) {
|
||||
PyErr_Format(PyExc_RuntimeError, "getmntent() failed");
|
||||
goto error;
|
||||
}
|
||||
py_tuple = Py_BuildValue("(ssss)",
|
||||
entry->mnt_fsname, // device
|
||||
entry->mnt_dir, // mount point
|
||||
entry->mnt_type, // fs type
|
||||
entry->mnt_opts); // options
|
||||
if (! py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
}
|
||||
endmntent(file);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
if (file != NULL)
|
||||
endmntent(file);
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_DECREF(py_retlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A wrapper around sysinfo(), return system memory usage statistics.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_linux_sysinfo(PyObject *self, PyObject *args)
|
||||
{
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) != 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
// note: boot time might also be determined from here
|
||||
return Py_BuildValue(
|
||||
"(KKKKKK)",
|
||||
(unsigned long long)info.totalram * info.mem_unit, // total
|
||||
(unsigned long long)info.freeram * info.mem_unit, // free
|
||||
(unsigned long long)info.bufferram * info.mem_unit, // buffer
|
||||
(unsigned long long)info.sharedram * info.mem_unit, // shared
|
||||
(unsigned long long)info.totalswap * info.mem_unit, // swap tot
|
||||
(unsigned long long)info.freeswap * info.mem_unit); // swap free
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return process CPU affinity as a Python list
|
||||
* The dual implementation exists because of:
|
||||
* https://github.com/giampaolo/psutil/issues/536
|
||||
*/
|
||||
|
||||
#ifdef CPU_ALLOC
|
||||
|
||||
static PyObject *
|
||||
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
||||
{
|
||||
int cpu, ncpus, count, cpucount_s;
|
||||
long pid;
|
||||
size_t setsize;
|
||||
cpu_set_t *mask = NULL;
|
||||
PyObject *res = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &pid))
|
||||
return NULL;
|
||||
ncpus = NCPUS_START;
|
||||
while (1) {
|
||||
setsize = CPU_ALLOC_SIZE(ncpus);
|
||||
mask = CPU_ALLOC(ncpus);
|
||||
if (mask == NULL)
|
||||
return PyErr_NoMemory();
|
||||
if (sched_getaffinity(pid, setsize, mask) == 0)
|
||||
break;
|
||||
CPU_FREE(mask);
|
||||
if (errno != EINVAL)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
if (ncpus > INT_MAX / 2) {
|
||||
PyErr_SetString(PyExc_OverflowError, "could not allocate "
|
||||
"a large enough CPU set");
|
||||
return NULL;
|
||||
}
|
||||
ncpus = ncpus * 2;
|
||||
}
|
||||
|
||||
res = PyList_New(0);
|
||||
if (res == NULL)
|
||||
goto error;
|
||||
|
||||
cpucount_s = CPU_COUNT_S(setsize, mask);
|
||||
for (cpu = 0, count = cpucount_s; count; cpu++) {
|
||||
if (CPU_ISSET_S(cpu, setsize, mask)) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *cpu_num = PyLong_FromLong(cpu);
|
||||
#else
|
||||
PyObject *cpu_num = PyInt_FromLong(cpu);
|
||||
#endif
|
||||
if (cpu_num == NULL)
|
||||
goto error;
|
||||
if (PyList_Append(res, cpu_num)) {
|
||||
Py_DECREF(cpu_num);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(cpu_num);
|
||||
--count;
|
||||
}
|
||||
}
|
||||
CPU_FREE(mask);
|
||||
return res;
|
||||
|
||||
error:
|
||||
if (mask)
|
||||
CPU_FREE(mask);
|
||||
Py_XDECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
/*
|
||||
* Alternative implementation in case CPU_ALLOC is not defined.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
||||
{
|
||||
cpu_set_t cpuset;
|
||||
unsigned int len = sizeof(cpu_set_t);
|
||||
long pid;
|
||||
int i;
|
||||
PyObject* py_retlist = NULL;
|
||||
PyObject *py_cpu_num = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &pid))
|
||||
return NULL;
|
||||
CPU_ZERO(&cpuset);
|
||||
if (sched_getaffinity(pid, len, &cpuset) < 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
|
||||
py_retlist = PyList_New(0);
|
||||
if (py_retlist == NULL)
|
||||
goto error;
|
||||
for (i = 0; i < CPU_SETSIZE; ++i) {
|
||||
if (CPU_ISSET(i, &cpuset)) {
|
||||
py_cpu_num = Py_BuildValue("i", i);
|
||||
if (py_cpu_num == NULL)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_cpu_num))
|
||||
goto error;
|
||||
Py_DECREF(py_cpu_num);
|
||||
}
|
||||
}
|
||||
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_cpu_num);
|
||||
Py_DECREF(py_retlist);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set process CPU affinity; expects a bitmask
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
|
||||
{
|
||||
cpu_set_t cpu_set;
|
||||
size_t len;
|
||||
long pid;
|
||||
int i, seq_len;
|
||||
PyObject *py_cpu_set;
|
||||
PyObject *py_cpu_seq = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set))
|
||||
return NULL;
|
||||
|
||||
if (!PySequence_Check(py_cpu_set)) {
|
||||
PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s",
|
||||
Py_TYPE(py_cpu_set)->tp_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer");
|
||||
if (!py_cpu_seq)
|
||||
goto error;
|
||||
seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq);
|
||||
CPU_ZERO(&cpu_set);
|
||||
for (i = 0; i < seq_len; i++) {
|
||||
PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i);
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
long value = PyLong_AsLong(item);
|
||||
#else
|
||||
long value = PyInt_AsLong(item);
|
||||
#endif
|
||||
if (value == -1 && PyErr_Occurred())
|
||||
goto error;
|
||||
CPU_SET(value, &cpu_set);
|
||||
}
|
||||
|
||||
len = sizeof(cpu_set);
|
||||
if (sched_setaffinity(pid, len, &cpu_set)) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_DECREF(py_cpu_seq);
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
if (py_cpu_seq != NULL)
|
||||
Py_DECREF(py_cpu_seq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return currently connected users as a list of tuples.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_users(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *ret_list = PyList_New(0);
|
||||
PyObject *tuple = NULL;
|
||||
PyObject *user_proc = NULL;
|
||||
struct utmp *ut;
|
||||
|
||||
if (ret_list == NULL)
|
||||
return NULL;
|
||||
setutent();
|
||||
while (NULL != (ut = getutent())) {
|
||||
tuple = NULL;
|
||||
user_proc = NULL;
|
||||
if (ut->ut_type == USER_PROCESS)
|
||||
user_proc = Py_True;
|
||||
else
|
||||
user_proc = Py_False;
|
||||
tuple = Py_BuildValue(
|
||||
"(sssfO)",
|
||||
ut->ut_user, // username
|
||||
ut->ut_line, // tty
|
||||
ut->ut_host, // hostname
|
||||
(float)ut->ut_tv.tv_sec, // tstamp
|
||||
user_proc // (bool) user process
|
||||
);
|
||||
if (! tuple)
|
||||
goto error;
|
||||
if (PyList_Append(ret_list, tuple))
|
||||
goto error;
|
||||
Py_DECREF(tuple);
|
||||
}
|
||||
endutent();
|
||||
return ret_list;
|
||||
|
||||
error:
|
||||
Py_XDECREF(tuple);
|
||||
Py_XDECREF(user_proc);
|
||||
Py_DECREF(ret_list);
|
||||
endutent();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return stats about a particular network
|
||||
* interface. References:
|
||||
* https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py
|
||||
* http://www.i-scream.org/libstatgrab/
|
||||
*/
|
||||
static PyObject*
|
||||
psutil_net_if_stats(PyObject* self, PyObject* args)
|
||||
{
|
||||
char *nic_name;
|
||||
int sock = 0;
|
||||
int ret;
|
||||
int duplex;
|
||||
int speed;
|
||||
int mtu;
|
||||
struct ifreq ifr;
|
||||
struct ethtool_cmd ethcmd;
|
||||
PyObject *py_is_up = NULL;
|
||||
PyObject *py_ret = NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||
return NULL;
|
||||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == -1)
|
||||
goto error;
|
||||
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||
|
||||
// is up?
|
||||
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
|
||||
if (ret == -1)
|
||||
goto error;
|
||||
if ((ifr.ifr_flags & IFF_UP) != 0)
|
||||
py_is_up = Py_True;
|
||||
else
|
||||
py_is_up = Py_False;
|
||||
Py_INCREF(py_is_up);
|
||||
|
||||
// MTU
|
||||
ret = ioctl(sock, SIOCGIFMTU, &ifr);
|
||||
if (ret == -1)
|
||||
goto error;
|
||||
mtu = ifr.ifr_mtu;
|
||||
|
||||
// duplex and speed
|
||||
memset(ðcmd, 0, sizeof ethcmd);
|
||||
ethcmd.cmd = ETHTOOL_GSET;
|
||||
ifr.ifr_data = (caddr_t)ðcmd;
|
||||
ret = ioctl(sock, SIOCETHTOOL, &ifr);
|
||||
|
||||
if (ret != -1) {
|
||||
duplex = ethcmd.duplex;
|
||||
speed = ethcmd.speed;
|
||||
}
|
||||
else {
|
||||
if (errno == EOPNOTSUPP) {
|
||||
// we typically get here in case of wi-fi cards
|
||||
duplex = DUPLEX_UNKNOWN;
|
||||
speed = 0;
|
||||
}
|
||||
else {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
py_ret = Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu);
|
||||
if (!py_ret)
|
||||
goto error;
|
||||
Py_DECREF(py_is_up);
|
||||
return py_ret;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_is_up);
|
||||
if (sock != 0)
|
||||
close(sock);
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Define the psutil C module methods and initialize the module.
|
||||
*/
|
||||
static PyMethodDef
|
||||
PsutilMethods[] =
|
||||
{
|
||||
// --- per-process functions
|
||||
|
||||
#if PSUTIL_HAVE_IOPRIO
|
||||
{"proc_ioprio_get", psutil_proc_ioprio_get, METH_VARARGS,
|
||||
"Get process I/O priority"},
|
||||
{"proc_ioprio_set", psutil_proc_ioprio_set, METH_VARARGS,
|
||||
"Set process I/O priority"},
|
||||
#endif
|
||||
{"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS,
|
||||
"Return process CPU affinity as a Python long (the bitmask)."},
|
||||
{"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS,
|
||||
"Set process CPU affinity; expects a bitmask."},
|
||||
|
||||
// --- system related functions
|
||||
|
||||
{"disk_partitions", psutil_disk_partitions, METH_VARARGS,
|
||||
"Return disk mounted partitions as a list of tuples including "
|
||||
"device, mount point and filesystem type"},
|
||||
{"users", psutil_users, METH_VARARGS,
|
||||
"Return currently connected users as a list of tuples"},
|
||||
{"net_if_stats", psutil_net_if_stats, METH_VARARGS,
|
||||
"Return NIC stats (isup, duplex, speed, mtu)"},
|
||||
|
||||
// --- linux specific
|
||||
|
||||
{"linux_sysinfo", psutil_linux_sysinfo, METH_VARARGS,
|
||||
"A wrapper around sysinfo(), return system memory usage statistics"},
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
{"linux_prlimit", psutil_linux_prlimit, METH_VARARGS,
|
||||
"Get or set process resource limits."},
|
||||
#endif
|
||||
|
||||
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
struct module_state {
|
||||
PyObject *error;
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
|
||||
#else
|
||||
#define GETSTATE(m) (&_state)
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
static int
|
||||
psutil_linux_traverse(PyObject *m, visitproc visit, void *arg) {
|
||||
Py_VISIT(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
psutil_linux_clear(PyObject *m) {
|
||||
Py_CLEAR(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct PyModuleDef
|
||||
moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"psutil_linux",
|
||||
NULL,
|
||||
sizeof(struct module_state),
|
||||
PsutilMethods,
|
||||
NULL,
|
||||
psutil_linux_traverse,
|
||||
psutil_linux_clear,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
|
||||
PyMODINIT_FUNC PyInit__psutil_linux(void)
|
||||
|
||||
#else
|
||||
#define INITERROR return
|
||||
|
||||
void init_psutil_linux(void)
|
||||
#endif
|
||||
{
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *module = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
|
||||
#endif
|
||||
|
||||
|
||||
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
PyModule_AddIntConstant(module, "RLIM_INFINITY", RLIM_INFINITY);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_DATA", RLIMIT_DATA);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_FSIZE", RLIMIT_FSIZE);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_LOCKS", RLIMIT_LOCKS);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_NOFILE", RLIMIT_NOFILE);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK);
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE);
|
||||
#endif
|
||||
#ifdef RLIMIT_NICE
|
||||
PyModule_AddIntConstant(module, "RLIMIT_NICE", RLIMIT_NICE);
|
||||
#endif
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
PyModule_AddIntConstant(module, "RLIMIT_RTPRIO", RLIMIT_RTPRIO);
|
||||
#endif
|
||||
#ifdef RLIMIT_RTTIME
|
||||
PyModule_AddIntConstant(module, "RLIMIT_RTTIME", RLIMIT_RTTIME);
|
||||
#endif
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
PyModule_AddIntConstant(module, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING);
|
||||
#endif
|
||||
#endif
|
||||
PyModule_AddIntConstant(module, "DUPLEX_HALF", DUPLEX_HALF);
|
||||
PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL);
|
||||
PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN);
|
||||
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return module;
|
||||
#endif
|
||||
}
|
||||
21
python/psutil/psutil/_psutil_linux.h
Normal file
21
python/psutil/psutil/_psutil_linux.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
// process
|
||||
|
||||
static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_ioprio_get(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_ioprio_get(PyObject* self, PyObject* args);
|
||||
|
||||
// system
|
||||
|
||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_linux_sysinfo(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
|
||||
1808
python/psutil/psutil/_psutil_osx.c
Normal file
1808
python/psutil/psutil/_psutil_osx.c
Normal file
File diff suppressed because it is too large
Load diff
41
python/psutil/psutil/_psutil_osx.h
Normal file
41
python/psutil/psutil/_psutil_osx.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
// --- per-process functions
|
||||
static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_connections(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_gids(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_name(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_ppid(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_status(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_uids(PyObject* self, PyObject* args);
|
||||
|
||||
// --- system-related functions
|
||||
static PyObject* psutil_boot_time(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_pids(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
|
||||
531
python/psutil/psutil/_psutil_posix.c
Normal file
531
python/psutil/psutil/_psutil_posix.c
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Functions specific to all POSIX compliant platforms.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#ifdef __linux
|
||||
#include <netdb.h>
|
||||
#include <linux/if_packet.h>
|
||||
#endif // end linux
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun)
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include "_psutil_posix.h"
|
||||
|
||||
|
||||
/*
|
||||
* Given a PID return process priority as a Python integer.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_posix_getpriority(PyObject *self, PyObject *args)
|
||||
{
|
||||
long pid;
|
||||
int priority;
|
||||
errno = 0;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
return NULL;
|
||||
priority = getpriority(PRIO_PROCESS, pid);
|
||||
if (errno != 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
return Py_BuildValue("i", priority);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a PID and a value change process priority.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_posix_setpriority(PyObject *self, PyObject *args)
|
||||
{
|
||||
long pid;
|
||||
int priority;
|
||||
int retval;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "li", &pid, &priority))
|
||||
return NULL;
|
||||
retval = setpriority(PRIO_PROCESS, pid, priority);
|
||||
if (retval == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Translate a sockaddr struct into a Python string.
|
||||
* Return None if address family is not AF_INET* or AF_PACKET.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_convert_ipaddr(struct sockaddr *addr, int family)
|
||||
{
|
||||
char buf[NI_MAXHOST];
|
||||
int err;
|
||||
int addrlen;
|
||||
int n;
|
||||
size_t len;
|
||||
const char *data;
|
||||
char *ptr;
|
||||
|
||||
if (addr == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
else if (family == AF_INET || family == AF_INET6) {
|
||||
if (family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
err = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
if (err != 0) {
|
||||
// XXX we get here on FreeBSD when processing 'lo' / AF_INET6
|
||||
// broadcast. Not sure what to do other than returning None.
|
||||
// ifconfig does not show anything BTW.
|
||||
//PyErr_Format(PyExc_RuntimeError, gai_strerror(err));
|
||||
//return NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
else {
|
||||
return Py_BuildValue("s", buf);
|
||||
}
|
||||
}
|
||||
#ifdef __linux
|
||||
else if (family == AF_PACKET) {
|
||||
struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
|
||||
len = lladdr->sll_halen;
|
||||
data = (const char *)lladdr->sll_addr;
|
||||
}
|
||||
#endif
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
else if (addr->sa_family == AF_LINK) {
|
||||
// Note: prior to Python 3.4 socket module does not expose
|
||||
// AF_LINK so we'll do.
|
||||
struct sockaddr_dl *dladdr = (struct sockaddr_dl *)addr;
|
||||
len = dladdr->sdl_alen;
|
||||
data = LLADDR(dladdr);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
// unknown family
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
// AF_PACKET or AF_LINK
|
||||
if (len > 0) {
|
||||
ptr = buf;
|
||||
for (n = 0; n < len; ++n) {
|
||||
sprintf(ptr, "%02x:", data[n] & 0xff);
|
||||
ptr += 3;
|
||||
}
|
||||
*--ptr = '\0';
|
||||
return Py_BuildValue("s", buf);
|
||||
}
|
||||
else {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return NICs information a-la ifconfig as a list of tuples.
|
||||
* TODO: on Solaris we won't get any MAC address.
|
||||
*/
|
||||
static PyObject*
|
||||
psutil_net_if_addrs(PyObject* self, PyObject* args)
|
||||
{
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int family;
|
||||
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
PyObject *py_tuple = NULL;
|
||||
PyObject *py_address = NULL;
|
||||
PyObject *py_netmask = NULL;
|
||||
PyObject *py_broadcast = NULL;
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (getifaddrs(&ifaddr) == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (!ifa->ifa_addr)
|
||||
continue;
|
||||
family = ifa->ifa_addr->sa_family;
|
||||
py_address = psutil_convert_ipaddr(ifa->ifa_addr, family);
|
||||
// If the primary address can't be determined just skip it.
|
||||
// I've never seen this happen on Linux but I did on FreeBSD.
|
||||
if (py_address == Py_None)
|
||||
continue;
|
||||
if (py_address == NULL)
|
||||
goto error;
|
||||
py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family);
|
||||
if (py_netmask == NULL)
|
||||
goto error;
|
||||
#ifdef __linux
|
||||
py_broadcast = psutil_convert_ipaddr(ifa->ifa_ifu.ifu_broadaddr, family);
|
||||
#else
|
||||
py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family);
|
||||
#endif
|
||||
if (py_broadcast == NULL)
|
||||
goto error;
|
||||
py_tuple = Py_BuildValue(
|
||||
"(siOOO)",
|
||||
ifa->ifa_name,
|
||||
family,
|
||||
py_address,
|
||||
py_netmask,
|
||||
py_broadcast
|
||||
);
|
||||
|
||||
if (! py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_DECREF(py_address);
|
||||
Py_DECREF(py_netmask);
|
||||
Py_DECREF(py_broadcast);
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
if (ifaddr != NULL)
|
||||
freeifaddrs(ifaddr);
|
||||
Py_DECREF(py_retlist);
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_XDECREF(py_address);
|
||||
Py_XDECREF(py_netmask);
|
||||
Py_XDECREF(py_broadcast);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* net_if_stats() implementation. This is here because it is common
|
||||
* to both OSX and FreeBSD and I didn't know where else to put it.
|
||||
*/
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
|
||||
#include <sys/sockio.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if.h>
|
||||
|
||||
int psutil_get_nic_speed(int ifm_active) {
|
||||
// Determine NIC speed. Taken from:
|
||||
// http://www.i-scream.org/libstatgrab/
|
||||
// Assuming only ETHER devices
|
||||
switch(IFM_TYPE(ifm_active)) {
|
||||
case IFM_ETHER:
|
||||
switch(IFM_SUBTYPE(ifm_active)) {
|
||||
#if defined(IFM_HPNA_1) && ((!defined(IFM_10G_LR)) \
|
||||
|| (IFM_10G_LR != IFM_HPNA_1))
|
||||
// HomePNA 1.0 (1Mb/s)
|
||||
case(IFM_HPNA_1):
|
||||
return 1;
|
||||
#endif
|
||||
// 10 Mbit
|
||||
case(IFM_10_T): // 10BaseT - RJ45
|
||||
case(IFM_10_2): // 10Base2 - Thinnet
|
||||
case(IFM_10_5): // 10Base5 - AUI
|
||||
case(IFM_10_STP): // 10BaseT over shielded TP
|
||||
case(IFM_10_FL): // 10baseFL - Fiber
|
||||
return 10;
|
||||
// 100 Mbit
|
||||
case(IFM_100_TX): // 100BaseTX - RJ45
|
||||
case(IFM_100_FX): // 100BaseFX - Fiber
|
||||
case(IFM_100_T4): // 100BaseT4 - 4 pair cat 3
|
||||
case(IFM_100_VG): // 100VG-AnyLAN
|
||||
case(IFM_100_T2): // 100BaseT2
|
||||
return 100;
|
||||
// 1000 Mbit
|
||||
case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber
|
||||
case(IFM_1000_LX): // 1000baseLX - single-mode fiber
|
||||
case(IFM_1000_CX): // 1000baseCX - 150ohm STP
|
||||
#if defined(IFM_1000_TX) && !defined(OPENBSD)
|
||||
// FreeBSD 4 and others (but NOT OpenBSD)?
|
||||
case(IFM_1000_TX):
|
||||
#endif
|
||||
#ifdef IFM_1000_FX
|
||||
case(IFM_1000_FX):
|
||||
#endif
|
||||
#ifdef IFM_1000_T
|
||||
case(IFM_1000_T):
|
||||
#endif
|
||||
return 1000;
|
||||
#if defined(IFM_10G_SR) || defined(IFM_10G_LR) || defined(IFM_10G_CX4) \
|
||||
|| defined(IFM_10G_T)
|
||||
#ifdef IFM_10G_SR
|
||||
case(IFM_10G_SR):
|
||||
#endif
|
||||
#ifdef IFM_10G_LR
|
||||
case(IFM_10G_LR):
|
||||
#endif
|
||||
#ifdef IFM_10G_CX4
|
||||
case(IFM_10G_CX4):
|
||||
#endif
|
||||
#ifdef IFM_10G_TWINAX
|
||||
case(IFM_10G_TWINAX):
|
||||
#endif
|
||||
#ifdef IFM_10G_TWINAX_LONG
|
||||
case(IFM_10G_TWINAX_LONG):
|
||||
#endif
|
||||
#ifdef IFM_10G_T
|
||||
case(IFM_10G_T):
|
||||
#endif
|
||||
return 10000;
|
||||
#endif
|
||||
#if defined(IFM_2500_SX)
|
||||
#ifdef IFM_2500_SX
|
||||
case(IFM_2500_SX):
|
||||
#endif
|
||||
return 2500;
|
||||
#endif // any 2.5GBit stuff...
|
||||
// We don't know what it is
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef IFM_TOKEN
|
||||
case IFM_TOKEN:
|
||||
switch(IFM_SUBTYPE(ifm_active)) {
|
||||
case IFM_TOK_STP4: // Shielded twisted pair 4m - DB9
|
||||
case IFM_TOK_UTP4: // Unshielded twisted pair 4m - RJ45
|
||||
return 4;
|
||||
case IFM_TOK_STP16: // Shielded twisted pair 16m - DB9
|
||||
case IFM_TOK_UTP16: // Unshielded twisted pair 16m - RJ45
|
||||
return 16;
|
||||
#if defined(IFM_TOK_STP100) || defined(IFM_TOK_UTP100)
|
||||
#ifdef IFM_TOK_STP100
|
||||
case IFM_TOK_STP100: // Shielded twisted pair 100m - DB9
|
||||
#endif
|
||||
#ifdef IFM_TOK_UTP100
|
||||
case IFM_TOK_UTP100: // Unshielded twisted pair 100m - RJ45
|
||||
#endif
|
||||
return 100;
|
||||
#endif
|
||||
// We don't know what it is
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef IFM_FDDI
|
||||
case IFM_FDDI:
|
||||
switch(IFM_SUBTYPE(ifm_active)) {
|
||||
// We don't know what it is
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case IFM_IEEE80211:
|
||||
switch(IFM_SUBTYPE(ifm_active)) {
|
||||
case IFM_IEEE80211_FH1: // Frequency Hopping 1Mbps
|
||||
case IFM_IEEE80211_DS1: // Direct Sequence 1Mbps
|
||||
return 1;
|
||||
case IFM_IEEE80211_FH2: // Frequency Hopping 2Mbps
|
||||
case IFM_IEEE80211_DS2: // Direct Sequence 2Mbps
|
||||
return 2;
|
||||
case IFM_IEEE80211_DS5: // Direct Sequence 5Mbps
|
||||
return 5;
|
||||
case IFM_IEEE80211_DS11: // Direct Sequence 11Mbps
|
||||
return 11;
|
||||
case IFM_IEEE80211_DS22: // Direct Sequence 22Mbps
|
||||
return 22;
|
||||
// We don't know what it is
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return stats about a particular network interface.
|
||||
* References:
|
||||
* http://www.i-scream.org/libstatgrab/
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_net_if_stats(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *nic_name;
|
||||
int sock = 0;
|
||||
int ret;
|
||||
int duplex;
|
||||
int speed;
|
||||
int mtu;
|
||||
struct ifreq ifr;
|
||||
struct ifmediareq ifmed;
|
||||
|
||||
PyObject *py_is_up = NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||
return NULL;
|
||||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == -1)
|
||||
goto error;
|
||||
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||
|
||||
// is up?
|
||||
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
|
||||
if (ret == -1)
|
||||
goto error;
|
||||
if ((ifr.ifr_flags & IFF_UP) != 0)
|
||||
py_is_up = Py_True;
|
||||
else
|
||||
py_is_up = Py_False;
|
||||
Py_INCREF(py_is_up);
|
||||
|
||||
// MTU
|
||||
ret = ioctl(sock, SIOCGIFMTU, &ifr);
|
||||
if (ret == -1)
|
||||
goto error;
|
||||
mtu = ifr.ifr_mtu;
|
||||
|
||||
// speed / duplex
|
||||
memset(&ifmed, 0, sizeof(struct ifmediareq));
|
||||
strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name));
|
||||
ret = ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed);
|
||||
if (ret == -1) {
|
||||
speed = 0;
|
||||
duplex = 0;
|
||||
}
|
||||
else {
|
||||
speed = psutil_get_nic_speed(ifmed.ifm_active);
|
||||
if ((ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active)
|
||||
duplex = 2;
|
||||
else if ((ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active)
|
||||
duplex = 1;
|
||||
else
|
||||
duplex = 0;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
Py_DECREF(py_is_up);
|
||||
|
||||
return Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu);
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_is_up);
|
||||
if (sock != 0)
|
||||
close(sock);
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
#endif // net_if_stats() implementation
|
||||
|
||||
|
||||
/*
|
||||
* define the psutil C module methods and initialize the module.
|
||||
*/
|
||||
static PyMethodDef
|
||||
PsutilMethods[] =
|
||||
{
|
||||
{"getpriority", psutil_posix_getpriority, METH_VARARGS,
|
||||
"Return process priority"},
|
||||
{"setpriority", psutil_posix_setpriority, METH_VARARGS,
|
||||
"Set process priority"},
|
||||
{"net_if_addrs", psutil_net_if_addrs, METH_VARARGS,
|
||||
"Retrieve NICs information"},
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
{"net_if_stats", psutil_net_if_stats, METH_VARARGS,
|
||||
"Return NIC stats."},
|
||||
#endif
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
struct module_state {
|
||||
PyObject *error;
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
|
||||
#else
|
||||
#define GETSTATE(m) (&_state)
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
static int
|
||||
psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) {
|
||||
Py_VISIT(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
psutil_posix_clear(PyObject *m) {
|
||||
Py_CLEAR(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"psutil_posix",
|
||||
NULL,
|
||||
sizeof(struct module_state),
|
||||
PsutilMethods,
|
||||
NULL,
|
||||
psutil_posix_traverse,
|
||||
psutil_posix_clear,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
|
||||
PyMODINIT_FUNC PyInit__psutil_posix(void)
|
||||
|
||||
#else
|
||||
#define INITERROR return
|
||||
|
||||
void init_psutil_posix(void)
|
||||
#endif
|
||||
{
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *module = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__sun)
|
||||
PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
|
||||
#endif
|
||||
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return module;
|
||||
#endif
|
||||
}
|
||||
15
python/psutil/psutil/_psutil_posix.h
Normal file
15
python/psutil/psutil/_psutil_posix.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_posix_getpriority(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_posix_setpriority(PyObject* self, PyObject* args);
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
|
||||
#endif
|
||||
1389
python/psutil/psutil/_psutil_sunos.c
Normal file
1389
python/psutil/psutil/_psutil_sunos.c
Normal file
File diff suppressed because it is too large
Load diff
28
python/psutil/psutil/_psutil_sunos.h
Normal file
28
python/psutil/psutil/_psutil_sunos.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
// processes
|
||||
static PyObject* psutil_proc_basic_info(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cred(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_name_and_args(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_query_thread(PyObject* self, PyObject* args);
|
||||
|
||||
// system
|
||||
static PyObject* psutil_boot_time(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_connections(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
|
||||
3405
python/psutil/psutil/_psutil_windows.c
Normal file
3405
python/psutil/psutil/_psutil_windows.c
Normal file
File diff suppressed because it is too large
Load diff
68
python/psutil/psutil/_psutil_windows.h
Normal file
68
python/psutil/psutil/_psutil_windows.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
|
||||
// --- per-process functions
|
||||
|
||||
static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_info(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_is_suspended(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_kill(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_memory_info_2(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_name(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_num_handles(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_priority_get(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_priority_set(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_resume(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_suspend(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_username(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_wait(PyObject* self, PyObject* args);
|
||||
|
||||
#if (PSUTIL_WINVER >= 0x0600) // Windows Vista
|
||||
static PyObject* psutil_proc_io_priority_get(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_proc_io_priority_set(PyObject* self, PyObject* args);
|
||||
#endif
|
||||
|
||||
// --- system-related functions
|
||||
|
||||
static PyObject* psutil_boot_time(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_disk_usage(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_connections(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_pid_exists(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_pids(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_ppid_map(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args);
|
||||
static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
|
||||
|
||||
// --- windows API bindings
|
||||
|
||||
static PyObject* psutil_win32_QueryDosDevice(PyObject* self, PyObject* args);
|
||||
|
||||
// --- internal
|
||||
|
||||
int psutil_proc_suspend_or_resume(DWORD pid, int suspend);
|
||||
548
python/psutil/psutil/_pswindows.py
Normal file
548
python/psutil/psutil/_pswindows.py
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Windows platform implementation."""
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from . import _psutil_windows as cext
|
||||
from ._common import conn_tmap, usage_percent, isfile_strict
|
||||
from ._common import sockfam_to_enum, socktype_to_enum
|
||||
from ._compat import PY3, xrange, lru_cache, long
|
||||
from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS,
|
||||
BELOW_NORMAL_PRIORITY_CLASS,
|
||||
HIGH_PRIORITY_CLASS,
|
||||
IDLE_PRIORITY_CLASS,
|
||||
NORMAL_PRIORITY_CLASS,
|
||||
REALTIME_PRIORITY_CLASS)
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
import enum
|
||||
else:
|
||||
enum = None
|
||||
|
||||
# process priority constants, import from __init__.py:
|
||||
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
|
||||
__extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
|
||||
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
|
||||
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
|
||||
"CONN_DELETE_TCB",
|
||||
"AF_LINK",
|
||||
]
|
||||
|
||||
# --- module level constants (gets pushed up to psutil module)
|
||||
|
||||
CONN_DELETE_TCB = "DELETE_TCB"
|
||||
WAIT_TIMEOUT = 0x00000102 # 258 in decimal
|
||||
ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES,
|
||||
cext.ERROR_ACCESS_DENIED])
|
||||
if enum is None:
|
||||
AF_LINK = -1
|
||||
else:
|
||||
AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1})
|
||||
AF_LINK = AddressFamily.AF_LINK
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED,
|
||||
cext.MIB_TCP_STATE_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.MIB_TCP_STATE_SYN_RCVD: _common.CONN_SYN_RECV,
|
||||
cext.MIB_TCP_STATE_FIN_WAIT1: _common.CONN_FIN_WAIT1,
|
||||
cext.MIB_TCP_STATE_FIN_WAIT2: _common.CONN_FIN_WAIT2,
|
||||
cext.MIB_TCP_STATE_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.MIB_TCP_STATE_CLOSED: _common.CONN_CLOSE,
|
||||
cext.MIB_TCP_STATE_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.MIB_TCP_STATE_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.MIB_TCP_STATE_LISTEN: _common.CONN_LISTEN,
|
||||
cext.MIB_TCP_STATE_CLOSING: _common.CONN_CLOSING,
|
||||
cext.MIB_TCP_STATE_DELETE_TCB: CONN_DELETE_TCB,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
if enum is not None:
|
||||
class Priority(enum.IntEnum):
|
||||
ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS
|
||||
BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS
|
||||
HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS
|
||||
IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS
|
||||
NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS
|
||||
REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS
|
||||
|
||||
globals().update(Priority.__members__)
|
||||
|
||||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle'])
|
||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||
pextmem = namedtuple(
|
||||
'pextmem', ['num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool',
|
||||
'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool',
|
||||
'pagefile', 'peak_pagefile', 'private'])
|
||||
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss'])
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||
ntpinfo = namedtuple(
|
||||
'ntpinfo', ['num_handles', 'ctx_switches', 'user_time', 'kernel_time',
|
||||
'create_time', 'num_threads', 'io_rcount', 'io_wcount',
|
||||
'io_rbytes', 'io_wbytes'])
|
||||
|
||||
# set later from __init__.py
|
||||
NoSuchProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
@lru_cache(maxsize=512)
|
||||
def _win32_QueryDosDevice(s):
|
||||
return cext.win32_QueryDosDevice(s)
|
||||
|
||||
|
||||
def _convert_raw_path(s):
|
||||
# convert paths using native DOS format like:
|
||||
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
|
||||
# into: "C:\Windows\systemew\file.txt"
|
||||
if PY3 and not isinstance(s, str):
|
||||
s = s.decode('utf8')
|
||||
rawdrive = '\\'.join(s.split('\\')[:3])
|
||||
driveletter = _win32_QueryDosDevice(rawdrive)
|
||||
return os.path.join(driveletter, s[len(rawdrive):])
|
||||
|
||||
|
||||
# --- public functions
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
"""System virtual memory as a namedtuple."""
|
||||
mem = cext.virtual_mem()
|
||||
totphys, availphys, totpagef, availpagef, totvirt, freevirt = mem
|
||||
#
|
||||
total = totphys
|
||||
avail = availphys
|
||||
free = availphys
|
||||
used = total - avail
|
||||
percent = usage_percent((total - avail), total, _round=1)
|
||||
return svmem(total, avail, percent, used, free)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
|
||||
mem = cext.virtual_mem()
|
||||
total = mem[2]
|
||||
free = mem[3]
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
return _common.sswap(total, used, free, percent, 0, 0)
|
||||
|
||||
|
||||
def disk_usage(path):
|
||||
"""Return disk usage associated with path."""
|
||||
try:
|
||||
total, free = cext.disk_usage(path)
|
||||
except WindowsError:
|
||||
if not os.path.exists(path):
|
||||
msg = "No such file or directory: '%s'" % path
|
||||
raise OSError(errno.ENOENT, msg)
|
||||
raise
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
return _common.sdiskusage(total, used, free, percent)
|
||||
|
||||
|
||||
def disk_partitions(all):
|
||||
"""Return disk partitions."""
|
||||
rawlist = cext.disk_partitions(all)
|
||||
return [_common.sdiskpart(*x) for x in rawlist]
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system CPU times as a named tuple."""
|
||||
user, system, idle = cext.cpu_times()
|
||||
return scputimes(user, system, idle)
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system per-CPU times as a list of named tuples."""
|
||||
ret = []
|
||||
for cpu_t in cext.per_cpu_times():
|
||||
user, system, idle = cpu_t
|
||||
item = scputimes(user, system, idle)
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
return cext.cpu_count_logical()
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
return cext.cpu_count_phys()
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def net_connections(kind, _pid=-1):
|
||||
"""Return socket connections. If pid == -1 return system-wide
|
||||
connections (as opposed to connections opened by one process only).
|
||||
"""
|
||||
if kind not in conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
families, types = conn_tmap[kind]
|
||||
rawlist = cext.net_connections(_pid, families, types)
|
||||
ret = set()
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status, pid = item
|
||||
status = TCP_STATUSES[status]
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
if _pid == -1:
|
||||
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
|
||||
else:
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
ret = cext.net_if_stats()
|
||||
for name, items in ret.items():
|
||||
isup, duplex, speed, mtu = items
|
||||
if hasattr(_common, 'NicDuplex'):
|
||||
duplex = _common.NicDuplex(duplex)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
for item in rawlist:
|
||||
user, hostname, tstamp = item
|
||||
nt = _common.suser(user, None, hostname, tstamp)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
pids = cext.pids
|
||||
pid_exists = cext.pid_exists
|
||||
net_io_counters = cext.net_io_counters
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
ppid_map = cext.ppid_map # not meant to be public
|
||||
net_if_addrs = cext.net_if_addrs
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Decorator which translates bare OSError and WindowsError
|
||||
exceptions into NoSuchProcess and AccessDenied.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
# support for private module import
|
||||
if NoSuchProcess is None or AccessDenied is None:
|
||||
raise
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
if err.errno == errno.ESRCH:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
"""Return process name, which on Windows is always the final
|
||||
part of the executable.
|
||||
"""
|
||||
# This is how PIDs 0 and 4 are always represented in taskmgr
|
||||
# and process-hacker.
|
||||
if self.pid == 0:
|
||||
return "System Idle Process"
|
||||
elif self.pid == 4:
|
||||
return "System"
|
||||
else:
|
||||
try:
|
||||
# Note: this will fail with AD for most PIDs owned
|
||||
# by another user but it's faster.
|
||||
return os.path.basename(self.exe())
|
||||
except AccessDenied:
|
||||
return cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
# Note: os.path.exists(path) may return False even if the file
|
||||
# is there, see:
|
||||
# http://stackoverflow.com/questions/3112546/os-path-exists-lies
|
||||
|
||||
# see https://github.com/giampaolo/psutil/issues/414
|
||||
# see https://github.com/giampaolo/psutil/issues/528
|
||||
if self.pid in (0, 4):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
return _convert_raw_path(cext.proc_exe(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
return cext.proc_cmdline(self.pid)
|
||||
|
||||
def ppid(self):
|
||||
try:
|
||||
return ppid_map()[self.pid]
|
||||
except KeyError:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
|
||||
def _get_raw_meminfo(self):
|
||||
try:
|
||||
return cext.proc_memory_info(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
# TODO: the C ext can probably be refactored in order
|
||||
# to get this from cext.proc_info()
|
||||
return cext.proc_memory_info_2(self.pid)
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
# on Windows RSS == WorkingSetSize and VSM == PagefileUsage
|
||||
# fields of PROCESS_MEMORY_COUNTERS struct:
|
||||
# http://msdn.microsoft.com/en-us/library/windows/desktop/
|
||||
# ms684877(v=vs.85).aspx
|
||||
t = self._get_raw_meminfo()
|
||||
return _common.pmem(t[2], t[7])
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info_ex(self):
|
||||
return pextmem(*self._get_raw_meminfo())
|
||||
|
||||
def memory_maps(self):
|
||||
try:
|
||||
raw = cext.proc_memory_maps(self.pid)
|
||||
except OSError as err:
|
||||
# XXX - can't use wrap_exceptions decorator as we're
|
||||
# returning a generator; probably needs refactoring.
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
if err.errno == errno.ESRCH:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise
|
||||
else:
|
||||
for addr, perm, path, rss in raw:
|
||||
path = _convert_raw_path(path)
|
||||
addr = hex(addr)
|
||||
yield (addr, perm, path, rss)
|
||||
|
||||
@wrap_exceptions
|
||||
def kill(self):
|
||||
return cext.proc_kill(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
if timeout is None:
|
||||
timeout = cext.INFINITE
|
||||
else:
|
||||
# WaitForSingleObject() expects time in milliseconds
|
||||
timeout = int(timeout * 1000)
|
||||
ret = cext.proc_wait(self.pid, timeout)
|
||||
if ret == WAIT_TIMEOUT:
|
||||
# support for private module import
|
||||
if TimeoutExpired is None:
|
||||
raise RuntimeError("timeout expired")
|
||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def username(self):
|
||||
if self.pid in (0, 4):
|
||||
return 'NT AUTHORITY\\SYSTEM'
|
||||
return cext.proc_username(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
# special case for kernel process PIDs; return system boot time
|
||||
if self.pid in (0, 4):
|
||||
return boot_time()
|
||||
try:
|
||||
return cext.proc_create_time(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
return ntpinfo(*cext.proc_info(self.pid)).create_time
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return ntpinfo(*cext.proc_info(self.pid)).num_threads
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
try:
|
||||
ret = cext.proc_cpu_times(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
nt = ntpinfo(*cext.proc_info(self.pid))
|
||||
ret = (nt.user_time, nt.kernel_time)
|
||||
else:
|
||||
raise
|
||||
return _common.pcputimes(*ret)
|
||||
|
||||
@wrap_exceptions
|
||||
def suspend(self):
|
||||
return cext.proc_suspend(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def resume(self):
|
||||
return cext.proc_resume(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
if self.pid in (0, 4):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
# return a normalized pathname since the native C function appends
|
||||
# "\\" at the and of the path
|
||||
path = cext.proc_cwd(self.pid)
|
||||
return os.path.normpath(path)
|
||||
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
if self.pid in (0, 4):
|
||||
return []
|
||||
retlist = []
|
||||
# Filenames come in in native format like:
|
||||
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
|
||||
# Convert the first part in the corresponding drive letter
|
||||
# (e.g. "C:\") by using Windows's QueryDosDevice()
|
||||
raw_file_names = cext.proc_open_files(self.pid)
|
||||
for _file in raw_file_names:
|
||||
_file = _convert_raw_path(_file)
|
||||
if isfile_strict(_file) and _file not in retlist:
|
||||
ntuple = _common.popenfile(_file, -1)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
return net_connections(kind, _pid=self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
value = cext.proc_priority_get(self.pid)
|
||||
if enum is not None:
|
||||
value = Priority(value)
|
||||
return value
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
return cext.proc_priority_set(self.pid, value)
|
||||
|
||||
# available on Windows >= Vista
|
||||
if hasattr(cext, "proc_io_priority_get"):
|
||||
@wrap_exceptions
|
||||
def ionice_get(self):
|
||||
return cext.proc_io_priority_get(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def ionice_set(self, value, _):
|
||||
if _:
|
||||
raise TypeError("set_proc_ionice() on Windows takes only "
|
||||
"1 argument (2 given)")
|
||||
if value not in (2, 1, 0):
|
||||
raise ValueError("value must be 2 (normal), 1 (low) or 0 "
|
||||
"(very low); got %r" % value)
|
||||
return cext.proc_io_priority_set(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def io_counters(self):
|
||||
try:
|
||||
ret = cext.proc_io_counters(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
nt = ntpinfo(*cext.proc_info(self.pid))
|
||||
ret = (nt.io_rcount, nt.io_wcount, nt.io_rbytes, nt.io_wbytes)
|
||||
else:
|
||||
raise
|
||||
return _common.pio(*ret)
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
suspended = cext.proc_is_suspended(self.pid)
|
||||
if suspended:
|
||||
return _common.STATUS_STOPPED
|
||||
else:
|
||||
return _common.STATUS_RUNNING
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_affinity_get(self):
|
||||
def from_bitmask(x):
|
||||
return [i for i in xrange(64) if (1 << i) & x]
|
||||
bitmask = cext.proc_cpu_affinity_get(self.pid)
|
||||
return from_bitmask(bitmask)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_affinity_set(self, value):
|
||||
def to_bitmask(l):
|
||||
if not l:
|
||||
raise ValueError("invalid argument %r" % l)
|
||||
out = 0
|
||||
for b in l:
|
||||
out |= 2 ** b
|
||||
return out
|
||||
|
||||
# SetProcessAffinityMask() states that ERROR_INVALID_PARAMETER
|
||||
# is returned for an invalid CPU but this seems not to be true,
|
||||
# therefore we check CPUs validy beforehand.
|
||||
allcpus = list(range(len(per_cpu_times())))
|
||||
for cpu in value:
|
||||
if cpu not in allcpus:
|
||||
if not isinstance(cpu, (int, long)):
|
||||
raise TypeError(
|
||||
"invalid CPU %r; an integer is required" % cpu)
|
||||
else:
|
||||
raise ValueError("invalid CPU %r" % cpu)
|
||||
|
||||
bitmask = to_bitmask(value)
|
||||
cext.proc_cpu_affinity_set(self.pid, bitmask)
|
||||
|
||||
@wrap_exceptions
|
||||
def num_handles(self):
|
||||
try:
|
||||
return cext.proc_num_handles(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
return ntpinfo(*cext.proc_info(self.pid)).num_handles
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
ctx_switches = ntpinfo(*cext.proc_info(self.pid)).ctx_switches
|
||||
# only voluntary ctx switches are supported
|
||||
return _common.pctxsw(ctx_switches, 0)
|
||||
265
python/psutil/psutil/arch/bsd/process_info.c
Normal file
265
python/psutil/psutil/arch/bsd/process_info.c
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Helper functions related to fetching process information.
|
||||
* Used by _psutil_bsd module methods.
|
||||
*/
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/proc.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "process_info.h"
|
||||
|
||||
|
||||
/*
|
||||
* Returns a list of all BSD processes on the system. This routine
|
||||
* allocates the list and puts it in *procList and a count of the
|
||||
* number of entries in *procCount. You are responsible for freeing
|
||||
* this list (use "free" from System framework).
|
||||
* On success, the function returns 0.
|
||||
* On error, the function returns a BSD errno value.
|
||||
*/
|
||||
int
|
||||
psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount)
|
||||
{
|
||||
int err;
|
||||
struct kinfo_proc *result;
|
||||
int done;
|
||||
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
|
||||
// Declaring name as const requires us to cast it when passing it to
|
||||
// sysctl because the prototype doesn't include the const modifier.
|
||||
size_t length;
|
||||
|
||||
assert( procList != NULL);
|
||||
assert(*procList == NULL);
|
||||
assert(procCount != NULL);
|
||||
|
||||
*procCount = 0;
|
||||
|
||||
/*
|
||||
* We start by calling sysctl with result == NULL and length == 0.
|
||||
* That will succeed, and set length to the appropriate length.
|
||||
* We then allocate a buffer of that size and call sysctl again
|
||||
* with that buffer. If that succeeds, we're done. If that fails
|
||||
* with ENOMEM, we have to throw away our buffer and loop. Note
|
||||
* that the loop causes use to call sysctl with NULL again; this
|
||||
* is necessary because the ENOMEM failure case sets length to
|
||||
* the amount of data returned, not the amount of data that
|
||||
* could have been returned.
|
||||
*/
|
||||
result = NULL;
|
||||
done = 0;
|
||||
do {
|
||||
assert(result == NULL);
|
||||
// Call sysctl with a NULL buffer.
|
||||
length = 0;
|
||||
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1,
|
||||
NULL, &length, NULL, 0);
|
||||
if (err == -1)
|
||||
err = errno;
|
||||
|
||||
// Allocate an appropriately sized buffer based on the results
|
||||
// from the previous call.
|
||||
if (err == 0) {
|
||||
result = malloc(length);
|
||||
if (result == NULL)
|
||||
err = ENOMEM;
|
||||
}
|
||||
|
||||
// Call sysctl again with the new buffer. If we get an ENOMEM
|
||||
// error, toss away our buffer and start again.
|
||||
if (err == 0) {
|
||||
err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1,
|
||||
result, &length, NULL, 0);
|
||||
if (err == -1)
|
||||
err = errno;
|
||||
if (err == 0) {
|
||||
done = 1;
|
||||
}
|
||||
else if (err == ENOMEM) {
|
||||
assert(result != NULL);
|
||||
free(result);
|
||||
result = NULL;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
} while (err == 0 && ! done);
|
||||
|
||||
// Clean up and establish post conditions.
|
||||
if (err != 0 && result != NULL) {
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
*procList = result;
|
||||
*procCount = length / sizeof(struct kinfo_proc);
|
||||
|
||||
assert((err == 0) == (*procList != NULL));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
char
|
||||
*psutil_get_cmd_path(long pid, size_t *pathsize)
|
||||
{
|
||||
int mib[4];
|
||||
char *path;
|
||||
size_t size = 0;
|
||||
|
||||
/*
|
||||
* Make a sysctl() call to get the raw argument space of the process.
|
||||
*/
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PATHNAME;
|
||||
mib[3] = pid;
|
||||
|
||||
// call with a null buffer first to determine if we need a buffer
|
||||
if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1)
|
||||
return NULL;
|
||||
|
||||
path = malloc(size);
|
||||
if (path == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*pathsize = size;
|
||||
if (sysctl(mib, 4, path, &size, NULL, 0) == -1) {
|
||||
free(path);
|
||||
return NULL; // Insufficient privileges
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* XXX no longer used; it probably makese sense to remove it.
|
||||
* Borrowed from psi Python System Information project
|
||||
*
|
||||
* Get command arguments and environment variables.
|
||||
*
|
||||
* Based on code from ps.
|
||||
*
|
||||
* Returns:
|
||||
* 0 for success;
|
||||
* -1 for failure (Exception raised);
|
||||
* 1 for insufficient privileges.
|
||||
*/
|
||||
char
|
||||
*psutil_get_cmd_args(long pid, size_t *argsize)
|
||||
{
|
||||
int mib[4], argmax;
|
||||
size_t size = sizeof(argmax);
|
||||
char *procargs = NULL;
|
||||
|
||||
// Get the maximum process arguments size.
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_ARGMAX;
|
||||
|
||||
size = sizeof(argmax);
|
||||
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
|
||||
return NULL;
|
||||
|
||||
// Allocate space for the arguments.
|
||||
procargs = (char *)malloc(argmax);
|
||||
if (procargs == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a sysctl() call to get the raw argument space of the process.
|
||||
*/
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_ARGS;
|
||||
mib[3] = pid;
|
||||
|
||||
size = argmax;
|
||||
if (sysctl(mib, 4, procargs, &size, NULL, 0) == -1) {
|
||||
free(procargs);
|
||||
return NULL; // Insufficient privileges
|
||||
}
|
||||
|
||||
// return string and set the length of arguments
|
||||
*argsize = size;
|
||||
return procargs;
|
||||
}
|
||||
|
||||
|
||||
// returns the command line as a python list object
|
||||
PyObject *
|
||||
psutil_get_arg_list(long pid)
|
||||
{
|
||||
char *argstr = NULL;
|
||||
int pos = 0;
|
||||
size_t argsize = 0;
|
||||
PyObject *retlist = Py_BuildValue("[]");
|
||||
PyObject *item = NULL;
|
||||
|
||||
if (pid < 0)
|
||||
return retlist;
|
||||
argstr = psutil_get_cmd_args(pid, &argsize);
|
||||
if (argstr == NULL)
|
||||
goto error;
|
||||
|
||||
// args are returned as a flattened string with \0 separators between
|
||||
// arguments add each string to the list then step forward to the next
|
||||
// separator
|
||||
if (argsize > 0) {
|
||||
while (pos < argsize) {
|
||||
item = Py_BuildValue("s", &argstr[pos]);
|
||||
if (!item)
|
||||
goto error;
|
||||
if (PyList_Append(retlist, item))
|
||||
goto error;
|
||||
Py_DECREF(item);
|
||||
pos = pos + strlen(&argstr[pos]) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(argstr);
|
||||
return retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(item);
|
||||
Py_DECREF(retlist);
|
||||
if (argstr != NULL)
|
||||
free(argstr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return 1 if PID exists in the current process list, else 0.
|
||||
*/
|
||||
int
|
||||
psutil_pid_exists(long pid)
|
||||
{
|
||||
int kill_ret;
|
||||
|
||||
if (pid < 0)
|
||||
return 0;
|
||||
// if kill returns success of permission denied we know it's a valid PID
|
||||
kill_ret = kill(pid , 0);
|
||||
if ((0 == kill_ret) || (EPERM == errno))
|
||||
return 1;
|
||||
// otherwise return 0 for PID not found
|
||||
return 0;
|
||||
}
|
||||
|
||||
15
python/psutil/psutil/arch/bsd/process_info.h
Normal file
15
python/psutil/psutil/arch/bsd/process_info.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
typedef struct kinfo_proc kinfo_proc;
|
||||
|
||||
char *psutil_get_cmd_args(long pid, size_t *argsize);
|
||||
char *psutil_get_cmd_path(long pid, size_t *pathsize);
|
||||
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
|
||||
int psutil_pid_exists(long pid);
|
||||
PyObject* psutil_get_arg_list(long pid);
|
||||
281
python/psutil/psutil/arch/osx/process_info.c
Normal file
281
python/psutil/psutil/arch/osx/process_info.c
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Helper functions related to fetching process information.
|
||||
* Used by _psutil_osx module methods.
|
||||
*/
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h> // for INT_MAX
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <libproc.h>
|
||||
|
||||
#include "process_info.h"
|
||||
#include "../../_psutil_common.h"
|
||||
|
||||
|
||||
/*
|
||||
* Return 1 if PID exists in the current process list, else 0.
|
||||
*/
|
||||
int
|
||||
psutil_pid_exists(long pid)
|
||||
{
|
||||
int kill_ret;
|
||||
|
||||
// save some time if it's an invalid PID
|
||||
if (pid < 0)
|
||||
return 0;
|
||||
// if kill returns success of permission denied we know it's a valid PID
|
||||
kill_ret = kill(pid , 0);
|
||||
if ( (0 == kill_ret) || (EPERM == errno))
|
||||
return 1;
|
||||
|
||||
// otherwise return 0 for PID not found
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns a list of all BSD processes on the system. This routine
|
||||
* allocates the list and puts it in *procList and a count of the
|
||||
* number of entries in *procCount. You are responsible for freeing
|
||||
* this list (use "free" from System framework).
|
||||
* On success, the function returns 0.
|
||||
* On error, the function returns a BSD errno value.
|
||||
*/
|
||||
int
|
||||
psutil_get_proc_list(kinfo_proc **procList, size_t *procCount)
|
||||
{
|
||||
// Declaring mib as const requires use of a cast since the
|
||||
// sysctl prototype doesn't include the const modifier.
|
||||
static const int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
|
||||
size_t size, size2;
|
||||
void *ptr;
|
||||
int err, lim = 8; // some limit
|
||||
|
||||
assert( procList != NULL);
|
||||
assert(*procList == NULL);
|
||||
assert(procCount != NULL);
|
||||
|
||||
*procCount = 0;
|
||||
|
||||
/*
|
||||
* We start by calling sysctl with ptr == NULL and size == 0.
|
||||
* That will succeed, and set size to the appropriate length.
|
||||
* We then allocate a buffer of at least that size and call
|
||||
* sysctl with that buffer. If that succeeds, we're done.
|
||||
* If that call fails with ENOMEM, we throw the buffer away
|
||||
* and try again.
|
||||
* Note that the loop calls sysctl with NULL again. This is
|
||||
* is necessary because the ENOMEM failure case sets size to
|
||||
* the amount of data returned, not the amount of data that
|
||||
* could have been returned.
|
||||
*/
|
||||
while (lim-- > 0) {
|
||||
size = 0;
|
||||
if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1)
|
||||
return errno;
|
||||
size2 = size + (size >> 3); // add some
|
||||
if (size2 > size) {
|
||||
ptr = malloc(size2);
|
||||
if (ptr == NULL)
|
||||
ptr = malloc(size);
|
||||
else
|
||||
size = size2;
|
||||
}
|
||||
else {
|
||||
ptr = malloc(size);
|
||||
}
|
||||
if (ptr == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
if (sysctl((int *)mib3, 3, ptr, &size, NULL, 0) == -1) {
|
||||
err = errno;
|
||||
free(ptr);
|
||||
if (err != ENOMEM)
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
*procList = (kinfo_proc *)ptr;
|
||||
*procCount = size / sizeof(kinfo_proc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
// Read the maximum argument size for processes
|
||||
int
|
||||
psutil_get_argmax()
|
||||
{
|
||||
int argmax;
|
||||
int mib[] = { CTL_KERN, KERN_ARGMAX };
|
||||
size_t size = sizeof(argmax);
|
||||
|
||||
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0)
|
||||
return argmax;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// return process args as a python list
|
||||
PyObject *
|
||||
psutil_get_arg_list(long pid)
|
||||
{
|
||||
int mib[3];
|
||||
int nargs;
|
||||
int len;
|
||||
char *procargs = NULL;
|
||||
char *arg_ptr;
|
||||
char *arg_end;
|
||||
char *curr_arg;
|
||||
size_t argmax;
|
||||
PyObject *arg = NULL;
|
||||
PyObject *arglist = NULL;
|
||||
|
||||
// special case for PID 0 (kernel_task) where cmdline cannot be fetched
|
||||
if (pid == 0)
|
||||
return Py_BuildValue("[]");
|
||||
|
||||
// read argmax and allocate memory for argument space.
|
||||
argmax = psutil_get_argmax();
|
||||
if (! argmax) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
procargs = (char *)malloc(argmax);
|
||||
if (NULL == procargs) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// read argument space
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = pid;
|
||||
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
|
||||
if (EINVAL == errno) {
|
||||
// EINVAL == access denied OR nonexistent PID
|
||||
if (psutil_pid_exists(pid))
|
||||
AccessDenied();
|
||||
else
|
||||
NoSuchProcess();
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
arg_end = &procargs[argmax];
|
||||
// copy the number of arguments to nargs
|
||||
memcpy(&nargs, procargs, sizeof(nargs));
|
||||
|
||||
arg_ptr = procargs + sizeof(nargs);
|
||||
len = strlen(arg_ptr);
|
||||
arg_ptr += len + 1;
|
||||
|
||||
if (arg_ptr == arg_end) {
|
||||
free(procargs);
|
||||
return Py_BuildValue("[]");
|
||||
}
|
||||
|
||||
// skip ahead to the first argument
|
||||
for (; arg_ptr < arg_end; arg_ptr++) {
|
||||
if (*arg_ptr != '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
// iterate through arguments
|
||||
curr_arg = arg_ptr;
|
||||
arglist = Py_BuildValue("[]");
|
||||
if (!arglist)
|
||||
goto error;
|
||||
while (arg_ptr < arg_end && nargs > 0) {
|
||||
if (*arg_ptr++ == '\0') {
|
||||
arg = Py_BuildValue("s", curr_arg);
|
||||
if (!arg)
|
||||
goto error;
|
||||
if (PyList_Append(arglist, arg))
|
||||
goto error;
|
||||
Py_DECREF(arg);
|
||||
// iterate to next arg and decrement # of args
|
||||
curr_arg = arg_ptr;
|
||||
nargs--;
|
||||
}
|
||||
}
|
||||
|
||||
free(procargs);
|
||||
return arglist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(arg);
|
||||
Py_XDECREF(arglist);
|
||||
if (procargs != NULL)
|
||||
free(procargs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
|
||||
{
|
||||
int mib[4];
|
||||
size_t len;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = pid;
|
||||
|
||||
// fetch the info with sysctl()
|
||||
len = sizeof(struct kinfo_proc);
|
||||
|
||||
// now read the data from sysctl
|
||||
if (sysctl(mib, 4, kp, &len, NULL, 0) == -1) {
|
||||
// raise an exception and throw errno as the error
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// sysctl succeeds but len is zero, happens when process has gone away
|
||||
if (len == 0) {
|
||||
NoSuchProcess();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A thin wrapper around proc_pidinfo()
|
||||
*/
|
||||
int
|
||||
psutil_proc_pidinfo(long pid, int flavor, void *pti, int size)
|
||||
{
|
||||
int ret = proc_pidinfo((int)pid, flavor, 0, pti, size);
|
||||
if (ret == 0) {
|
||||
if (! psutil_pid_exists(pid)) {
|
||||
NoSuchProcess();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
AccessDenied();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (ret != size) {
|
||||
AccessDenied();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
16
python/psutil/psutil/arch/osx/process_info.h
Normal file
16
python/psutil/psutil/arch/osx/process_info.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
typedef struct kinfo_proc kinfo_proc;
|
||||
|
||||
int psutil_get_argmax(void);
|
||||
int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp);
|
||||
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
|
||||
int psutil_pid_exists(long pid);
|
||||
int psutil_proc_pidinfo(long pid, int flavor, void *pti, int size);
|
||||
PyObject* psutil_get_arg_list(long pid);
|
||||
41
python/psutil/psutil/arch/windows/glpi.h
Normal file
41
python/psutil/psutil/arch/windows/glpi.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// mingw headers are missing this
|
||||
|
||||
typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP {
|
||||
RelationProcessorCore,
|
||||
RelationNumaNode,
|
||||
RelationCache,
|
||||
RelationProcessorPackage,
|
||||
RelationGroup,
|
||||
RelationAll=0xffff
|
||||
} LOGICAL_PROCESSOR_RELATIONSHIP;
|
||||
|
||||
typedef enum _PROCESSOR_CACHE_TYPE {
|
||||
CacheUnified,CacheInstruction,CacheData,CacheTrace
|
||||
} PROCESSOR_CACHE_TYPE;
|
||||
|
||||
typedef struct _CACHE_DESCRIPTOR {
|
||||
BYTE Level;
|
||||
BYTE Associativity;
|
||||
WORD LineSize;
|
||||
DWORD Size;
|
||||
PROCESSOR_CACHE_TYPE Type;
|
||||
} CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR;
|
||||
|
||||
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION {
|
||||
ULONG_PTR ProcessorMask;
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
|
||||
union {
|
||||
struct {
|
||||
BYTE Flags;
|
||||
} ProcessorCore;
|
||||
struct {
|
||||
DWORD NodeNumber;
|
||||
} NumaNode;
|
||||
CACHE_DESCRIPTOR Cache;
|
||||
ULONGLONG Reserved[2];
|
||||
};
|
||||
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION;
|
||||
|
||||
WINBASEAPI WINBOOL WINAPI
|
||||
GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,
|
||||
PDWORD ReturnedLength);
|
||||
41
python/psutil/psutil/arch/windows/inet_ntop.c
Normal file
41
python/psutil/psutil/arch/windows/inet_ntop.c
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#include "inet_ntop.h"
|
||||
|
||||
// From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/
|
||||
PCSTR
|
||||
WSAAPI
|
||||
inet_ntop(
|
||||
__in INT Family,
|
||||
__in PVOID pAddr,
|
||||
__out_ecount(StringBufSize) PSTR pStringBuf,
|
||||
__in size_t StringBufSize
|
||||
)
|
||||
{
|
||||
DWORD dwAddressLength = 0;
|
||||
struct sockaddr_storage srcaddr;
|
||||
struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr;
|
||||
struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr;
|
||||
|
||||
memset(&srcaddr, 0, sizeof(struct sockaddr_storage));
|
||||
srcaddr.ss_family = Family;
|
||||
|
||||
if (Family == AF_INET)
|
||||
{
|
||||
dwAddressLength = sizeof(struct sockaddr_in);
|
||||
memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr));
|
||||
} else if (Family == AF_INET6)
|
||||
{
|
||||
dwAddressLength = sizeof(struct sockaddr_in6);
|
||||
memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr));
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (WSAAddressToString((LPSOCKADDR) &srcaddr,
|
||||
dwAddressLength,
|
||||
0,
|
||||
pStringBuf,
|
||||
(LPDWORD) &StringBufSize) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
return pStringBuf;
|
||||
}
|
||||
10
python/psutil/psutil/arch/windows/inet_ntop.h
Normal file
10
python/psutil/psutil/arch/windows/inet_ntop.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include <ws2tcpip.h>
|
||||
|
||||
PCSTR
|
||||
WSAAPI
|
||||
inet_ntop(
|
||||
__in INT Family,
|
||||
__in PVOID pAddr,
|
||||
__out_ecount(StringBufSize) PSTR pStringBuf,
|
||||
__in size_t StringBufSize
|
||||
);
|
||||
228
python/psutil/psutil/arch/windows/ntextapi.h
Normal file
228
python/psutil/psutil/arch/windows/ntextapi.h
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#if !defined(__NTEXTAPI_H__)
|
||||
#define __NTEXTAPI_H__
|
||||
#include <winternl.h>
|
||||
|
||||
typedef enum _KTHREAD_STATE {
|
||||
Initialized,
|
||||
Ready,
|
||||
Running,
|
||||
Standby,
|
||||
Terminated,
|
||||
Waiting,
|
||||
Transition,
|
||||
DeferredReady,
|
||||
GateWait,
|
||||
MaximumThreadState
|
||||
} KTHREAD_STATE, *PKTHREAD_STATE;
|
||||
|
||||
typedef enum _KWAIT_REASON {
|
||||
Executive = 0,
|
||||
FreePage = 1,
|
||||
PageIn = 2,
|
||||
PoolAllocation = 3,
|
||||
DelayExecution = 4,
|
||||
Suspended = 5,
|
||||
UserRequest = 6,
|
||||
WrExecutive = 7,
|
||||
WrFreePage = 8,
|
||||
WrPageIn = 9,
|
||||
WrPoolAllocation = 10,
|
||||
WrDelayExecution = 11,
|
||||
WrSuspended = 12,
|
||||
WrUserRequest = 13,
|
||||
WrEventPair = 14,
|
||||
WrQueue = 15,
|
||||
WrLpcReceive = 16,
|
||||
WrLpcReply = 17,
|
||||
WrVirtualMemory = 18,
|
||||
WrPageOut = 19,
|
||||
WrRendezvous = 20,
|
||||
Spare2 = 21,
|
||||
Spare3 = 22,
|
||||
Spare4 = 23,
|
||||
Spare5 = 24,
|
||||
WrCalloutStack = 25,
|
||||
WrKernel = 26,
|
||||
WrResource = 27,
|
||||
WrPushLock = 28,
|
||||
WrMutex = 29,
|
||||
WrQuantumEnd = 30,
|
||||
WrDispatchInt = 31,
|
||||
WrPreempted = 32,
|
||||
WrYieldExecution = 33,
|
||||
WrFastMutex = 34,
|
||||
WrGuardedMutex = 35,
|
||||
WrRundown = 36,
|
||||
MaximumWaitReason = 37
|
||||
} KWAIT_REASON, *PKWAIT_REASON;
|
||||
|
||||
typedef struct _CLIENT_ID {
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID, *PCLIENT_ID;
|
||||
|
||||
typedef struct _SYSTEM_THREAD_INFORMATION {
|
||||
LARGE_INTEGER KernelTime;
|
||||
LARGE_INTEGER UserTime;
|
||||
LARGE_INTEGER CreateTime;
|
||||
ULONG WaitTime;
|
||||
PVOID StartAddress;
|
||||
CLIENT_ID ClientId;
|
||||
LONG Priority;
|
||||
LONG BasePriority;
|
||||
ULONG ContextSwitches;
|
||||
ULONG ThreadState;
|
||||
KWAIT_REASON WaitReason;
|
||||
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
|
||||
|
||||
typedef struct _TEB *PTEB;
|
||||
|
||||
// private
|
||||
typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
|
||||
SYSTEM_THREAD_INFORMATION ThreadInfo;
|
||||
PVOID StackBase;
|
||||
PVOID StackLimit;
|
||||
PVOID Win32StartAddress;
|
||||
PTEB TebBase;
|
||||
ULONG_PTR Reserved2;
|
||||
ULONG_PTR Reserved3;
|
||||
ULONG_PTR Reserved4;
|
||||
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
|
||||
|
||||
typedef struct _SYSTEM_PROCESS_INFORMATION2 {
|
||||
ULONG NextEntryOffset;
|
||||
ULONG NumberOfThreads;
|
||||
LARGE_INTEGER SpareLi1;
|
||||
LARGE_INTEGER SpareLi2;
|
||||
LARGE_INTEGER SpareLi3;
|
||||
LARGE_INTEGER CreateTime;
|
||||
LARGE_INTEGER UserTime;
|
||||
LARGE_INTEGER KernelTime;
|
||||
UNICODE_STRING ImageName;
|
||||
LONG BasePriority;
|
||||
HANDLE UniqueProcessId;
|
||||
HANDLE InheritedFromUniqueProcessId;
|
||||
ULONG HandleCount;
|
||||
ULONG SessionId;
|
||||
ULONG_PTR PageDirectoryBase;
|
||||
SIZE_T PeakVirtualSize;
|
||||
SIZE_T VirtualSize;
|
||||
DWORD PageFaultCount;
|
||||
SIZE_T PeakWorkingSetSize;
|
||||
SIZE_T WorkingSetSize;
|
||||
SIZE_T QuotaPeakPagedPoolUsage;
|
||||
SIZE_T QuotaPagedPoolUsage;
|
||||
SIZE_T QuotaPeakNonPagedPoolUsage;
|
||||
SIZE_T QuotaNonPagedPoolUsage;
|
||||
SIZE_T PagefileUsage;
|
||||
SIZE_T PeakPagefileUsage;
|
||||
SIZE_T PrivatePageCount;
|
||||
LARGE_INTEGER ReadOperationCount;
|
||||
LARGE_INTEGER WriteOperationCount;
|
||||
LARGE_INTEGER OtherOperationCount;
|
||||
LARGE_INTEGER ReadTransferCount;
|
||||
LARGE_INTEGER WriteTransferCount;
|
||||
LARGE_INTEGER OtherTransferCount;
|
||||
SYSTEM_THREAD_INFORMATION Threads[1];
|
||||
} SYSTEM_PROCESS_INFORMATION2, *PSYSTEM_PROCESS_INFORMATION2;
|
||||
|
||||
#define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2
|
||||
#define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2
|
||||
|
||||
|
||||
// ================================================
|
||||
// psutil.users() support
|
||||
// ================================================
|
||||
|
||||
typedef struct _WINSTATION_INFO {
|
||||
BYTE Reserved1[72];
|
||||
ULONG SessionId;
|
||||
BYTE Reserved2[4];
|
||||
FILETIME ConnectTime;
|
||||
FILETIME DisconnectTime;
|
||||
FILETIME LastInputTime;
|
||||
FILETIME LoginTime;
|
||||
BYTE Reserved3[1096];
|
||||
FILETIME CurrentTime;
|
||||
} WINSTATION_INFO, *PWINSTATION_INFO;
|
||||
|
||||
typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)
|
||||
(HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG);
|
||||
|
||||
|
||||
/*
|
||||
* NtQueryInformationProcess code taken from
|
||||
* http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/
|
||||
* typedefs needed to compile against ntdll functions not exposted in the API
|
||||
*/
|
||||
typedef LONG NTSTATUS;
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
|
||||
HANDLE ProcessHandle,
|
||||
DWORD ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
DWORD ProcessInformationLength,
|
||||
PDWORD ReturnLength
|
||||
);
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
|
||||
HANDLE ProcessHandle,
|
||||
DWORD ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
DWORD ProcessInformationLength
|
||||
);
|
||||
|
||||
|
||||
typedef enum _PROCESSINFOCLASS2 {
|
||||
_ProcessBasicInformation,
|
||||
ProcessQuotaLimits,
|
||||
ProcessIoCounters,
|
||||
ProcessVmCounters,
|
||||
ProcessTimes,
|
||||
ProcessBasePriority,
|
||||
ProcessRaisePriority,
|
||||
ProcessDebugPort,
|
||||
ProcessExceptionPort,
|
||||
ProcessAccessToken,
|
||||
ProcessLdtInformation,
|
||||
ProcessLdtSize,
|
||||
ProcessDefaultHardErrorMode,
|
||||
ProcessIoPortHandlers,
|
||||
ProcessPooledUsageAndLimits,
|
||||
ProcessWorkingSetWatch,
|
||||
ProcessUserModeIOPL,
|
||||
ProcessEnableAlignmentFaultFixup,
|
||||
ProcessPriorityClass,
|
||||
ProcessWx86Information,
|
||||
ProcessHandleCount,
|
||||
ProcessAffinityMask,
|
||||
ProcessPriorityBoost,
|
||||
ProcessDeviceMap,
|
||||
ProcessSessionInformation,
|
||||
ProcessForegroundInformation,
|
||||
_ProcessWow64Information,
|
||||
/* added after XP+ */
|
||||
ProcessImageFileName,
|
||||
ProcessLUIDDeviceMapsEnabled,
|
||||
ProcessBreakOnTermination,
|
||||
ProcessDebugObjectHandle,
|
||||
ProcessDebugFlags,
|
||||
ProcessHandleTracing,
|
||||
ProcessIoPriority,
|
||||
ProcessExecuteFlags,
|
||||
ProcessResourceManagement,
|
||||
ProcessCookie,
|
||||
ProcessImageInformation,
|
||||
MaxProcessInfoClass
|
||||
} PROCESSINFOCLASS2;
|
||||
|
||||
#define PROCESSINFOCLASS PROCESSINFOCLASS2
|
||||
#define ProcessBasicInformation _ProcessBasicInformation
|
||||
#define ProcessWow64Information _ProcessWow64Information
|
||||
|
||||
#endif // __NTEXTAPI_H__
|
||||
533
python/psutil/psutil/arch/windows/process_handles.c
Normal file
533
python/psutil/psutil/arch/windows/process_handles.c
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
#include "process_handles.h"
|
||||
|
||||
static _NtQuerySystemInformation __NtQuerySystemInformation = NULL;
|
||||
static _NtQueryObject __NtQueryObject = NULL;
|
||||
|
||||
CRITICAL_SECTION g_cs;
|
||||
BOOL g_initialized = FALSE;
|
||||
NTSTATUS g_status;
|
||||
HANDLE g_hFile = NULL;
|
||||
HANDLE g_hEvtStart = NULL;
|
||||
HANDLE g_hEvtFinish = NULL;
|
||||
HANDLE g_hThread = NULL;
|
||||
PUNICODE_STRING g_pNameBuffer = NULL;
|
||||
ULONG g_dwSize = 0;
|
||||
ULONG g_dwLength = 0;
|
||||
PVOID g_fiber = NULL;
|
||||
|
||||
|
||||
PVOID
|
||||
GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName)
|
||||
{
|
||||
return GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
psutil_get_open_files(long dwPid, HANDLE hProcess)
|
||||
{
|
||||
OSVERSIONINFO osvi;
|
||||
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&osvi);
|
||||
|
||||
// Threaded version only works for Vista+
|
||||
if (osvi.dwMajorVersion >= 6)
|
||||
return psutil_get_open_files_ntqueryobject(dwPid, hProcess);
|
||||
else
|
||||
return psutil_get_open_files_getmappedfilename(dwPid, hProcess);
|
||||
}
|
||||
|
||||
VOID
|
||||
psutil_get_open_files_init(BOOL threaded)
|
||||
{
|
||||
if (g_initialized == TRUE)
|
||||
return;
|
||||
|
||||
// Resolve the Windows API calls
|
||||
__NtQuerySystemInformation =
|
||||
GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation");
|
||||
__NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject");
|
||||
|
||||
// Create events for signalling work between threads
|
||||
if (threaded == TRUE) {
|
||||
g_hEvtStart = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
g_hEvtFinish = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
InitializeCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
g_initialized = TRUE;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
||||
DWORD dwInfoSize = 0x10000;
|
||||
DWORD dwRet = 0;
|
||||
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
|
||||
DWORD i = 0;
|
||||
BOOLEAN error = FALSE;
|
||||
PyObject* pyListFiles = NULL;
|
||||
PyObject* pyFilePath = NULL;
|
||||
DWORD dwWait = 0;
|
||||
|
||||
if (g_initialized == FALSE)
|
||||
psutil_get_open_files_init(TRUE);
|
||||
|
||||
// Due to the use of global variables, ensure only 1 call
|
||||
// to psutil_get_open_files() is running
|
||||
EnterCriticalSection(&g_cs);
|
||||
|
||||
if (__NtQuerySystemInformation == NULL ||
|
||||
__NtQueryObject == NULL ||
|
||||
g_hEvtStart == NULL ||
|
||||
g_hEvtFinish == NULL)
|
||||
|
||||
{
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Py_BuildValue raises an exception if NULL is returned
|
||||
pyListFiles = PyList_New(0);
|
||||
if (pyListFiles == NULL) {
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
do {
|
||||
if (pHandleInfo != NULL) {
|
||||
HeapFree(GetProcessHeap(), 0, pHandleInfo);
|
||||
pHandleInfo = NULL;
|
||||
}
|
||||
|
||||
// NtQuerySystemInformation won't give us the correct buffer size,
|
||||
// so we guess by doubling the buffer size.
|
||||
dwInfoSize *= 2;
|
||||
pHandleInfo = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
dwInfoSize);
|
||||
|
||||
if (pHandleInfo == NULL) {
|
||||
PyErr_NoMemory();
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
} while ((status = __NtQuerySystemInformation(
|
||||
SystemExtendedHandleInformation,
|
||||
pHandleInfo,
|
||||
dwInfoSize,
|
||||
&dwRet)) == STATUS_INFO_LENGTH_MISMATCH);
|
||||
|
||||
// NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH
|
||||
if (!NT_SUCCESS(status)) {
|
||||
PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status));
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < pHandleInfo->NumberOfHandles; i++) {
|
||||
hHandle = &pHandleInfo->Handles[i];
|
||||
|
||||
// Check if this hHandle belongs to the PID the user specified.
|
||||
if (hHandle->UniqueProcessId != (HANDLE)dwPid ||
|
||||
hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE)
|
||||
goto loop_cleanup;
|
||||
|
||||
if (!DuplicateHandle(hProcess,
|
||||
hHandle->HandleValue,
|
||||
GetCurrentProcess(),
|
||||
&g_hFile,
|
||||
0,
|
||||
TRUE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
/*
|
||||
printf("[%d] DuplicateHandle (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
// Guess buffer size is MAX_PATH + 1
|
||||
g_dwLength = (MAX_PATH+1) * sizeof(WCHAR);
|
||||
|
||||
do {
|
||||
// Release any previously allocated buffer
|
||||
if (g_pNameBuffer != NULL) {
|
||||
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
|
||||
g_pNameBuffer = NULL;
|
||||
g_dwSize = 0;
|
||||
}
|
||||
|
||||
// NtQueryObject puts the required buffer size in g_dwLength
|
||||
// WinXP edge case puts g_dwLength == 0, just skip this handle
|
||||
if (g_dwLength == 0)
|
||||
goto loop_cleanup;
|
||||
|
||||
g_dwSize = g_dwLength;
|
||||
if (g_dwSize > 0) {
|
||||
g_pNameBuffer = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
g_dwSize);
|
||||
|
||||
if (g_pNameBuffer == NULL)
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
dwWait = psutil_NtQueryObject();
|
||||
|
||||
// If the call does not return, skip this handle
|
||||
if (dwWait != WAIT_OBJECT_0)
|
||||
goto loop_cleanup;
|
||||
|
||||
} while (g_status == STATUS_INFO_LENGTH_MISMATCH);
|
||||
|
||||
// NtQueryObject stopped returning STATUS_INFO_LENGTH_MISMATCH
|
||||
if (!NT_SUCCESS(g_status))
|
||||
goto loop_cleanup;
|
||||
|
||||
// Convert to PyUnicode and append it to the return list
|
||||
if (g_pNameBuffer->Length > 0) {
|
||||
/*
|
||||
printf("[%d] Filename (%#x) %#d bytes: %S\n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
g_pNameBuffer->Length,
|
||||
g_pNameBuffer->Buffer);
|
||||
*/
|
||||
|
||||
pyFilePath = PyUnicode_FromWideChar(g_pNameBuffer->Buffer,
|
||||
g_pNameBuffer->Length/2);
|
||||
if (pyFilePath == NULL) {
|
||||
/*
|
||||
printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
error = TRUE;
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
if (PyList_Append(pyListFiles, pyFilePath)) {
|
||||
/*
|
||||
printf("[%d] PyList_Append (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
error = TRUE;
|
||||
goto loop_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
loop_cleanup:
|
||||
Py_XDECREF(pyFilePath);
|
||||
pyFilePath = NULL;
|
||||
|
||||
if (g_pNameBuffer != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
|
||||
g_pNameBuffer = NULL;
|
||||
g_dwSize = 0;
|
||||
g_dwLength = 0;
|
||||
|
||||
if (g_hFile != NULL)
|
||||
CloseHandle(g_hFile);
|
||||
g_hFile = NULL;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (g_pNameBuffer != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
|
||||
g_pNameBuffer = NULL;
|
||||
g_dwSize = 0;
|
||||
g_dwLength = 0;
|
||||
|
||||
if (g_hFile != NULL)
|
||||
CloseHandle(g_hFile);
|
||||
g_hFile = NULL;
|
||||
|
||||
if (pHandleInfo != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, pHandleInfo);
|
||||
pHandleInfo = NULL;
|
||||
|
||||
if (error) {
|
||||
Py_XDECREF(pyListFiles);
|
||||
pyListFiles = NULL;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_cs);
|
||||
|
||||
return pyListFiles;
|
||||
}
|
||||
|
||||
DWORD
|
||||
psutil_NtQueryObject()
|
||||
{
|
||||
DWORD dwWait = 0;
|
||||
|
||||
if (g_hThread == NULL)
|
||||
g_hThread = CreateThread(NULL,
|
||||
0,
|
||||
(LPTHREAD_START_ROUTINE)psutil_NtQueryObjectThread,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
if (g_hThread == NULL)
|
||||
return GetLastError();
|
||||
|
||||
// Signal the worker thread to start
|
||||
SetEvent(g_hEvtStart);
|
||||
|
||||
// Wait for the worker thread to finish
|
||||
dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT);
|
||||
|
||||
// If the thread hangs, kill it and cleanup
|
||||
if (dwWait == WAIT_TIMEOUT) {
|
||||
SuspendThread(g_hThread);
|
||||
TerminateThread(g_hThread, 1);
|
||||
WaitForSingleObject(g_hThread, INFINITE);
|
||||
CloseHandle(g_hThread);
|
||||
|
||||
// Cleanup Fiber
|
||||
if (g_fiber != NULL)
|
||||
DeleteFiber(g_fiber);
|
||||
g_fiber = NULL;
|
||||
|
||||
g_hThread = NULL;
|
||||
}
|
||||
|
||||
return dwWait;
|
||||
}
|
||||
|
||||
void
|
||||
psutil_NtQueryObjectThread()
|
||||
{
|
||||
// Prevent the thread stack from leaking when this
|
||||
// thread gets terminated due to NTQueryObject hanging
|
||||
g_fiber = ConvertThreadToFiber(NULL);
|
||||
|
||||
// Loop infinitely waiting for work
|
||||
while (TRUE) {
|
||||
WaitForSingleObject(g_hEvtStart, INFINITE);
|
||||
|
||||
g_status = __NtQueryObject(g_hFile,
|
||||
ObjectNameInformation,
|
||||
g_pNameBuffer,
|
||||
g_dwSize,
|
||||
&g_dwLength);
|
||||
SetEvent(g_hEvtFinish);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *
|
||||
psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
||||
DWORD dwInfoSize = 0x10000;
|
||||
DWORD dwRet = 0;
|
||||
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
|
||||
HANDLE hFile = NULL;
|
||||
HANDLE hMap = NULL;
|
||||
DWORD i = 0;
|
||||
BOOLEAN error = FALSE;
|
||||
PyObject* pyListFiles = NULL;
|
||||
PyObject* pyFilePath = NULL;
|
||||
ULONG dwSize = 0;
|
||||
LPVOID pMem = NULL;
|
||||
TCHAR pszFilename[MAX_PATH+1];
|
||||
|
||||
if (g_initialized == FALSE)
|
||||
psutil_get_open_files_init(FALSE);
|
||||
|
||||
if (__NtQuerySystemInformation == NULL || __NtQueryObject == NULL) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Py_BuildValue raises an exception if NULL is returned
|
||||
pyListFiles = PyList_New(0);
|
||||
if (pyListFiles == NULL) {
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
do {
|
||||
if (pHandleInfo != NULL) {
|
||||
HeapFree(GetProcessHeap(), 0, pHandleInfo);
|
||||
pHandleInfo = NULL;
|
||||
}
|
||||
|
||||
// NtQuerySystemInformation won't give us the correct buffer size,
|
||||
// so we guess by doubling the buffer size.
|
||||
dwInfoSize *= 2;
|
||||
pHandleInfo = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
dwInfoSize);
|
||||
|
||||
if (pHandleInfo == NULL) {
|
||||
PyErr_NoMemory();
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
} while ((status = __NtQuerySystemInformation(
|
||||
SystemExtendedHandleInformation,
|
||||
pHandleInfo,
|
||||
dwInfoSize,
|
||||
&dwRet)) == STATUS_INFO_LENGTH_MISMATCH);
|
||||
|
||||
// NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH
|
||||
if (!NT_SUCCESS(status)) {
|
||||
PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status));
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < pHandleInfo->NumberOfHandles; i++) {
|
||||
hHandle = &pHandleInfo->Handles[i];
|
||||
|
||||
// Check if this hHandle belongs to the PID the user specified.
|
||||
if (hHandle->UniqueProcessId != (HANDLE)dwPid ||
|
||||
hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE)
|
||||
goto loop_cleanup;
|
||||
|
||||
if (!DuplicateHandle(hProcess,
|
||||
hHandle->HandleValue,
|
||||
GetCurrentProcess(),
|
||||
&hFile,
|
||||
0,
|
||||
TRUE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
/*
|
||||
printf("[%d] DuplicateHandle (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMap == NULL) {
|
||||
/*
|
||||
printf("[%d] CreateFileMapping (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
pMem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 1);
|
||||
|
||||
if (pMem == NULL) {
|
||||
/*
|
||||
printf("[%d] MapViewOfFile (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
dwSize = GetMappedFileName(GetCurrentProcess(), pMem, pszFilename, MAX_PATH);
|
||||
if (dwSize == 0) {
|
||||
/*
|
||||
printf("[%d] GetMappedFileName (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
pszFilename[dwSize] = '\0';
|
||||
/*
|
||||
printf("[%d] Filename (%#x) %#d bytes: %S\n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
dwSize,
|
||||
pszFilename);
|
||||
*/
|
||||
|
||||
pyFilePath = PyUnicode_FromWideChar(pszFilename, dwSize);
|
||||
if (pyFilePath == NULL) {
|
||||
/*
|
||||
printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
error = TRUE;
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
if (PyList_Append(pyListFiles, pyFilePath)) {
|
||||
/*
|
||||
printf("[%d] PyList_Append (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
error = TRUE;
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
loop_cleanup:
|
||||
Py_XDECREF(pyFilePath);
|
||||
pyFilePath = NULL;
|
||||
|
||||
if (pMem != NULL)
|
||||
UnmapViewOfFile(pMem);
|
||||
pMem = NULL;
|
||||
|
||||
if (hMap != NULL)
|
||||
CloseHandle(hMap);
|
||||
hMap = NULL;
|
||||
|
||||
if (hFile != NULL)
|
||||
CloseHandle(hFile);
|
||||
hFile = NULL;
|
||||
|
||||
dwSize = 0;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (pMem != NULL)
|
||||
UnmapViewOfFile(pMem);
|
||||
pMem = NULL;
|
||||
|
||||
if (hMap != NULL)
|
||||
CloseHandle(hMap);
|
||||
hMap = NULL;
|
||||
|
||||
if (hFile != NULL)
|
||||
CloseHandle(hFile);
|
||||
hFile = NULL;
|
||||
|
||||
if (pHandleInfo != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, pHandleInfo);
|
||||
pHandleInfo = NULL;
|
||||
|
||||
if (error) {
|
||||
Py_XDECREF(pyListFiles);
|
||||
pyListFiles = NULL;
|
||||
}
|
||||
|
||||
return pyListFiles;
|
||||
}
|
||||
113
python/psutil/psutil/arch/windows/process_handles.h
Normal file
113
python/psutil/psutil/arch/windows/process_handles.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef __PROCESS_HANDLES_H__
|
||||
#define __PROCESS_HANDLES_H__
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include <Python.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <winternl.h>
|
||||
#include <psapi.h>
|
||||
|
||||
|
||||
#ifndef NT_SUCCESS
|
||||
#define NT_SUCCESS(x) ((x) >= 0)
|
||||
#endif
|
||||
|
||||
#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
|
||||
#define ObjectBasicInformation 0
|
||||
#define ObjectNameInformation 1
|
||||
#define ObjectTypeInformation 2
|
||||
#define HANDLE_TYPE_FILE 28
|
||||
#define NTQO_TIMEOUT 100
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
|
||||
ULONG SystemInformationClass,
|
||||
PVOID SystemInformation,
|
||||
ULONG SystemInformationLength,
|
||||
PULONG ReturnLength
|
||||
);
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtQueryObject)(
|
||||
HANDLE ObjectHandle,
|
||||
ULONG ObjectInformationClass,
|
||||
PVOID ObjectInformation,
|
||||
ULONG ObjectInformationLength,
|
||||
PULONG ReturnLength
|
||||
);
|
||||
|
||||
// Undocumented FILE_INFORMATION_CLASS: FileNameInformation
|
||||
static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64;
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
|
||||
{
|
||||
PVOID Object;
|
||||
HANDLE UniqueProcessId;
|
||||
HANDLE HandleValue;
|
||||
ULONG GrantedAccess;
|
||||
USHORT CreatorBackTraceIndex;
|
||||
USHORT ObjectTypeIndex;
|
||||
ULONG HandleAttributes;
|
||||
ULONG Reserved;
|
||||
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
|
||||
{
|
||||
ULONG_PTR NumberOfHandles;
|
||||
ULONG_PTR Reserved;
|
||||
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
|
||||
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
|
||||
|
||||
typedef enum _POOL_TYPE {
|
||||
NonPagedPool,
|
||||
PagedPool,
|
||||
NonPagedPoolMustSucceed,
|
||||
DontUseThisType,
|
||||
NonPagedPoolCacheAligned,
|
||||
PagedPoolCacheAligned,
|
||||
NonPagedPoolCacheAlignedMustS
|
||||
} POOL_TYPE, *PPOOL_TYPE;
|
||||
|
||||
typedef struct _OBJECT_TYPE_INFORMATION {
|
||||
UNICODE_STRING Name;
|
||||
ULONG TotalNumberOfObjects;
|
||||
ULONG TotalNumberOfHandles;
|
||||
ULONG TotalPagedPoolUsage;
|
||||
ULONG TotalNonPagedPoolUsage;
|
||||
ULONG TotalNamePoolUsage;
|
||||
ULONG TotalHandleTableUsage;
|
||||
ULONG HighWaterNumberOfObjects;
|
||||
ULONG HighWaterNumberOfHandles;
|
||||
ULONG HighWaterPagedPoolUsage;
|
||||
ULONG HighWaterNonPagedPoolUsage;
|
||||
ULONG HighWaterNamePoolUsage;
|
||||
ULONG HighWaterHandleTableUsage;
|
||||
ULONG InvalidAttributes;
|
||||
GENERIC_MAPPING GenericMapping;
|
||||
ULONG ValidAccess;
|
||||
BOOLEAN SecurityRequired;
|
||||
BOOLEAN MaintainHandleCount;
|
||||
USHORT MaintainTypeList;
|
||||
POOL_TYPE PoolType;
|
||||
ULONG PagedPoolUsage;
|
||||
ULONG NonPagedPoolUsage;
|
||||
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
|
||||
|
||||
PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName);
|
||||
VOID psutil_get_open_files_init(BOOL threaded);
|
||||
PyObject* psutil_get_open_files(long pid, HANDLE processHandle);
|
||||
PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess);
|
||||
PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess);
|
||||
DWORD psutil_NtQueryObject(void);
|
||||
void psutil_NtQueryObjectThread(void);
|
||||
|
||||
#endif // __PROCESS_HANDLES_H__
|
||||
435
python/psutil/psutil/arch/windows/process_info.c
Normal file
435
python/psutil/psutil/arch/windows/process_info.c
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Helper functions related to fetching process information. Used by
|
||||
* _psutil_windows module methods.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
#include <Psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#include "security.h"
|
||||
#include "process_info.h"
|
||||
#include "ntextapi.h"
|
||||
#include "../../_psutil_common.h"
|
||||
|
||||
|
||||
/*
|
||||
* A wrapper around OpenProcess setting NSP exception if process
|
||||
* no longer exists.
|
||||
* "pid" is the process pid, "dwDesiredAccess" is the first argument
|
||||
* exptected by OpenProcess.
|
||||
* Return a process handle or NULL.
|
||||
*/
|
||||
HANDLE
|
||||
psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
DWORD processExitCode = 0;
|
||||
|
||||
if (pid == 0) {
|
||||
// otherwise we'd get NoSuchProcess
|
||||
return AccessDenied();
|
||||
}
|
||||
|
||||
hProcess = OpenProcess(dwDesiredAccess, FALSE, pid);
|
||||
if (hProcess == NULL) {
|
||||
if (GetLastError() == ERROR_INVALID_PARAMETER)
|
||||
NoSuchProcess();
|
||||
else
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// make sure the process is running
|
||||
GetExitCodeProcess(hProcess, &processExitCode);
|
||||
if (processExitCode == 0) {
|
||||
NoSuchProcess();
|
||||
CloseHandle(hProcess);
|
||||
return NULL;
|
||||
}
|
||||
return hProcess;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Same as psutil_handle_from_pid_waccess but implicitly uses
|
||||
* PROCESS_QUERY_INFORMATION | PROCESS_VM_READ as dwDesiredAccess
|
||||
* parameter for OpenProcess.
|
||||
*/
|
||||
HANDLE
|
||||
psutil_handle_from_pid(DWORD pid) {
|
||||
DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
|
||||
return psutil_handle_from_pid_waccess(pid, dwDesiredAccess);
|
||||
}
|
||||
|
||||
|
||||
// fetch the PEB base address from NtQueryInformationProcess()
|
||||
PVOID
|
||||
psutil_get_peb_address(HANDLE ProcessHandle)
|
||||
{
|
||||
_NtQueryInformationProcess NtQueryInformationProcess =
|
||||
(_NtQueryInformationProcess)GetProcAddress(
|
||||
GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
|
||||
PROCESS_BASIC_INFORMATION pbi;
|
||||
|
||||
NtQueryInformationProcess(ProcessHandle, 0, &pbi, sizeof(pbi), NULL);
|
||||
return pbi.PebBaseAddress;
|
||||
}
|
||||
|
||||
|
||||
DWORD *
|
||||
psutil_get_pids(DWORD *numberOfReturnedPIDs) {
|
||||
// Win32 SDK says the only way to know if our process array
|
||||
// wasn't large enough is to check the returned size and make
|
||||
// sure that it doesn't match the size of the array.
|
||||
// If it does we allocate a larger array and try again
|
||||
|
||||
// Stores the actual array
|
||||
DWORD *procArray = NULL;
|
||||
DWORD procArrayByteSz;
|
||||
int procArraySz = 0;
|
||||
|
||||
// Stores the byte size of the returned array from enumprocesses
|
||||
DWORD enumReturnSz = 0;
|
||||
|
||||
do {
|
||||
procArraySz += 1024;
|
||||
free(procArray);
|
||||
procArrayByteSz = procArraySz * sizeof(DWORD);
|
||||
procArray = malloc(procArrayByteSz);
|
||||
if (procArray == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) {
|
||||
free(procArray);
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return NULL;
|
||||
}
|
||||
} while (enumReturnSz == procArraySz * sizeof(DWORD));
|
||||
|
||||
// The number of elements is the returned size / size of each element
|
||||
*numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD);
|
||||
|
||||
return procArray;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_pid_is_running(DWORD pid)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
DWORD exitCode;
|
||||
|
||||
// Special case for PID 0 System Idle Process
|
||||
if (pid == 0)
|
||||
return 1;
|
||||
if (pid < 0)
|
||||
return 0;
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
||||
FALSE, pid);
|
||||
if (NULL == hProcess) {
|
||||
// invalid parameter is no such process
|
||||
if (GetLastError() == ERROR_INVALID_PARAMETER) {
|
||||
CloseHandle(hProcess);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// access denied obviously means there's a process to deny access to...
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
||||
CloseHandle(hProcess);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CloseHandle(hProcess);
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (GetExitCodeProcess(hProcess, &exitCode)) {
|
||||
CloseHandle(hProcess);
|
||||
return (exitCode == STILL_ACTIVE);
|
||||
}
|
||||
|
||||
// access denied means there's a process there so we'll assume
|
||||
// it's running
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
||||
CloseHandle(hProcess);
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
CloseHandle(hProcess);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_pid_in_proclist(DWORD pid)
|
||||
{
|
||||
DWORD *proclist = NULL;
|
||||
DWORD numberOfReturnedPIDs;
|
||||
DWORD i;
|
||||
|
||||
proclist = psutil_get_pids(&numberOfReturnedPIDs);
|
||||
if (proclist == NULL)
|
||||
return -1;
|
||||
for (i = 0; i < numberOfReturnedPIDs; i++) {
|
||||
if (pid == proclist[i]) {
|
||||
free(proclist);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(proclist);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Check exit code from a process handle. Return FALSE on an error also
|
||||
// XXX - not used anymore
|
||||
int
|
||||
handlep_is_running(HANDLE hProcess)
|
||||
{
|
||||
DWORD dwCode;
|
||||
|
||||
if (NULL == hProcess)
|
||||
return 0;
|
||||
if (GetExitCodeProcess(hProcess, &dwCode)) {
|
||||
if (dwCode == STILL_ACTIVE)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* returns a Python list representing the arguments for the process
|
||||
* with given pid or NULL on error.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_get_arg_list(long pid)
|
||||
{
|
||||
int nArgs, i;
|
||||
LPWSTR *szArglist = NULL;
|
||||
HANDLE hProcess = NULL;
|
||||
PVOID pebAddress;
|
||||
PVOID rtlUserProcParamsAddress;
|
||||
UNICODE_STRING commandLine;
|
||||
WCHAR *commandLineContents = NULL;
|
||||
PyObject *arg = NULL;
|
||||
PyObject *arg_from_wchar = NULL;
|
||||
PyObject *argList = NULL;
|
||||
|
||||
hProcess = psutil_handle_from_pid(pid);
|
||||
if (hProcess == NULL)
|
||||
return NULL;
|
||||
pebAddress = psutil_get_peb_address(hProcess);
|
||||
|
||||
// get the address of ProcessParameters
|
||||
#ifdef _WIN64
|
||||
if (!ReadProcessMemory(hProcess, (PCHAR)pebAddress + 32,
|
||||
&rtlUserProcParamsAddress, sizeof(PVOID), NULL))
|
||||
#else
|
||||
if (!ReadProcessMemory(hProcess, (PCHAR)pebAddress + 0x10,
|
||||
&rtlUserProcParamsAddress, sizeof(PVOID), NULL))
|
||||
#endif
|
||||
{
|
||||
////printf("Could not read the address of ProcessParameters!\n");
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// read the CommandLine UNICODE_STRING structure
|
||||
#ifdef _WIN64
|
||||
if (!ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 112,
|
||||
&commandLine, sizeof(commandLine), NULL))
|
||||
#else
|
||||
if (!ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 0x40,
|
||||
&commandLine, sizeof(commandLine), NULL))
|
||||
#endif
|
||||
{
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
// allocate memory to hold the command line
|
||||
commandLineContents = (WCHAR *)malloc(commandLine.Length + 1);
|
||||
if (commandLineContents == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
|
||||
// read the command line
|
||||
if (!ReadProcessMemory(hProcess, commandLine.Buffer,
|
||||
commandLineContents, commandLine.Length, NULL))
|
||||
{
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Null-terminate the string to prevent wcslen from returning
|
||||
// incorrect length the length specifier is in characters, but
|
||||
// commandLine.Length is in bytes.
|
||||
commandLineContents[(commandLine.Length / sizeof(WCHAR))] = '\0';
|
||||
|
||||
// attempt tp parse the command line using Win32 API, fall back
|
||||
// on string cmdline version otherwise
|
||||
szArglist = CommandLineToArgvW(commandLineContents, &nArgs);
|
||||
if (NULL == szArglist) {
|
||||
// failed to parse arglist
|
||||
// encode as a UTF8 Python string object from WCHAR string
|
||||
arg_from_wchar = PyUnicode_FromWideChar(commandLineContents,
|
||||
commandLine.Length / 2);
|
||||
if (arg_from_wchar == NULL)
|
||||
goto error;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
argList = Py_BuildValue("N", PyUnicode_AsUTF8String(arg_from_wchar));
|
||||
#else
|
||||
argList = Py_BuildValue("N", PyUnicode_FromObject(arg_from_wchar));
|
||||
#endif
|
||||
if (!argList)
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
// arglist parsed as array of UNICODE_STRING, so convert each to
|
||||
// Python string object and add to arg list
|
||||
argList = Py_BuildValue("[]");
|
||||
if (argList == NULL)
|
||||
goto error;
|
||||
for (i = 0; i < nArgs; i++) {
|
||||
arg_from_wchar = NULL;
|
||||
arg = NULL;
|
||||
arg_from_wchar = PyUnicode_FromWideChar(szArglist[i],
|
||||
wcslen(szArglist[i]));
|
||||
if (arg_from_wchar == NULL)
|
||||
goto error;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
arg = PyUnicode_FromObject(arg_from_wchar);
|
||||
#else
|
||||
arg = PyUnicode_AsUTF8String(arg_from_wchar);
|
||||
#endif
|
||||
if (arg == NULL)
|
||||
goto error;
|
||||
Py_XDECREF(arg_from_wchar);
|
||||
if (PyList_Append(argList, arg))
|
||||
goto error;
|
||||
Py_XDECREF(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (szArglist != NULL)
|
||||
LocalFree(szArglist);
|
||||
free(commandLineContents);
|
||||
CloseHandle(hProcess);
|
||||
return argList;
|
||||
|
||||
error:
|
||||
Py_XDECREF(arg);
|
||||
Py_XDECREF(arg_from_wchar);
|
||||
Py_XDECREF(argList);
|
||||
if (hProcess != NULL)
|
||||
CloseHandle(hProcess);
|
||||
if (commandLineContents != NULL)
|
||||
free(commandLineContents);
|
||||
if (szArglist != NULL)
|
||||
LocalFree(szArglist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes))
|
||||
#define PH_NEXT_PROCESS(Process) ( \
|
||||
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \
|
||||
(PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \
|
||||
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \
|
||||
NULL)
|
||||
|
||||
const int STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
|
||||
const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L;
|
||||
|
||||
/*
|
||||
* Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure
|
||||
* fills the structure with various process information by using
|
||||
* NtQuerySystemInformation.
|
||||
* We use this as a fallback when faster functions fail with access
|
||||
* denied. This is slower because it iterates over all processes.
|
||||
* On success return 1, else 0 with Python exception already set.
|
||||
*/
|
||||
int
|
||||
psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
|
||||
PVOID *retBuffer)
|
||||
{
|
||||
static ULONG initialBufferSize = 0x4000;
|
||||
NTSTATUS status;
|
||||
PVOID buffer;
|
||||
ULONG bufferSize;
|
||||
PSYSTEM_PROCESS_INFORMATION process;
|
||||
|
||||
// get NtQuerySystemInformation
|
||||
typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG);
|
||||
NTQSI_PROC NtQuerySystemInformation;
|
||||
HINSTANCE hNtDll;
|
||||
hNtDll = LoadLibrary(TEXT("ntdll.dll"));
|
||||
NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
|
||||
hNtDll, "NtQuerySystemInformation");
|
||||
|
||||
bufferSize = initialBufferSize;
|
||||
buffer = malloc(bufferSize);
|
||||
if (buffer == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
status = NtQuerySystemInformation(SystemProcessInformation, buffer,
|
||||
bufferSize, &bufferSize);
|
||||
|
||||
if (status == STATUS_BUFFER_TOO_SMALL ||
|
||||
status == STATUS_INFO_LENGTH_MISMATCH)
|
||||
{
|
||||
free(buffer);
|
||||
buffer = malloc(bufferSize);
|
||||
if (buffer == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, "NtQuerySystemInformation() failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bufferSize <= 0x20000)
|
||||
initialBufferSize = bufferSize;
|
||||
|
||||
process = PH_FIRST_PROCESS(buffer);
|
||||
do {
|
||||
if (process->UniqueProcessId == (HANDLE)pid) {
|
||||
*retProcess = process;
|
||||
*retBuffer = buffer;
|
||||
return 1;
|
||||
}
|
||||
} while ( (process = PH_NEXT_PROCESS(process)) );
|
||||
|
||||
NoSuchProcess();
|
||||
goto error;
|
||||
|
||||
error:
|
||||
FreeLibrary(hNtDll);
|
||||
if (buffer != NULL)
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
26
python/psutil/psutil/arch/windows/process_info.h
Normal file
26
python/psutil/psutil/arch/windows/process_info.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#if !defined(__PROCESS_INFO_H)
|
||||
#define __PROCESS_INFO_H
|
||||
|
||||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
#include "security.h"
|
||||
#include "ntextapi.h"
|
||||
|
||||
DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs);
|
||||
HANDLE psutil_handle_from_pid(DWORD pid);
|
||||
HANDLE psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess);
|
||||
int psutil_handlep_is_running(HANDLE hProcess);
|
||||
int psutil_pid_in_proclist(DWORD pid);
|
||||
int psutil_pid_is_running(DWORD pid);
|
||||
PVOID psutil_get_peb_address(HANDLE ProcessHandle);
|
||||
PyObject* psutil_get_arg_list(long pid);
|
||||
int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
|
||||
PVOID *retBuffer);
|
||||
|
||||
#endif
|
||||
228
python/psutil/psutil/arch/windows/security.c
Normal file
228
python/psutil/psutil/arch/windows/security.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Security related functions for Windows platform (Set privileges such as
|
||||
* SeDebug), as well as security helper functions.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <Python.h>
|
||||
|
||||
|
||||
/*
|
||||
* Convert a process handle to a process token handle.
|
||||
*/
|
||||
HANDLE
|
||||
psutil_token_from_handle(HANDLE hProcess) {
|
||||
HANDLE hToken = NULL;
|
||||
|
||||
if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
return hToken;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* http://www.ddj.com/windows/184405986
|
||||
*
|
||||
* There's a way to determine whether we're running under the Local System
|
||||
* account. However (you guessed it), we have to call more Win32 functions to
|
||||
* determine this. Backing up through the code listing, we need to make another
|
||||
* call to GetTokenInformation, but instead of passing through the TOKEN_USER
|
||||
* constant, we pass through the TOKEN_PRIVILEGES constant. This value returns
|
||||
* an array of privileges that the account has in the environment. Iterating
|
||||
* through the array, we call the function LookupPrivilegeName looking for the
|
||||
* string “SeTcbPrivilege. If the function returns this string, then this
|
||||
* account has Local System privileges
|
||||
*/
|
||||
int
|
||||
psutil_has_system_privilege(HANDLE hProcess) {
|
||||
DWORD i;
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwRetval = 0;
|
||||
TCHAR privName[256];
|
||||
DWORD dwNameSize = 256;
|
||||
// PTOKEN_PRIVILEGES tp = NULL;
|
||||
BYTE *pBuffer = NULL;
|
||||
TOKEN_PRIVILEGES *tp = NULL;
|
||||
HANDLE hToken = psutil_token_from_handle(hProcess);
|
||||
|
||||
if (NULL == hToken)
|
||||
return -1;
|
||||
// call GetTokenInformation first to get the buffer size
|
||||
if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) {
|
||||
dwRetval = GetLastError();
|
||||
// if it failed for a reason other than the buffer, bail out
|
||||
if (dwRetval != ERROR_INSUFFICIENT_BUFFER ) {
|
||||
PyErr_SetFromWindowsErr(dwRetval);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate buffer and call GetTokenInformation again
|
||||
// tp = (PTOKEN_PRIVILEGES) GlobalAlloc(GPTR, dwSize);
|
||||
pBuffer = (BYTE *) malloc(dwSize);
|
||||
if (pBuffer == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! GetTokenInformation(hToken, TokenPrivileges, pBuffer,
|
||||
dwSize, &dwSize))
|
||||
{
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
free(pBuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// convert the BYTE buffer to a TOKEN_PRIVILEGES struct pointer
|
||||
tp = (TOKEN_PRIVILEGES *)pBuffer;
|
||||
|
||||
// check all the privileges looking for SeTcbPrivilege
|
||||
for (i = 0; i < tp->PrivilegeCount; i++) {
|
||||
// reset the buffer contents and the buffer size
|
||||
strcpy(privName, "");
|
||||
dwNameSize = sizeof(privName) / sizeof(TCHAR);
|
||||
if (! LookupPrivilegeName(NULL,
|
||||
&tp->Privileges[i].Luid,
|
||||
(LPTSTR)privName,
|
||||
&dwNameSize))
|
||||
{
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
free(pBuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if we find the SeTcbPrivilege then it's a LocalSystem process
|
||||
if (! lstrcmpi(privName, TEXT("SeTcbPrivilege"))) {
|
||||
free(pBuffer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(pBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege)
|
||||
{
|
||||
TOKEN_PRIVILEGES tp;
|
||||
LUID luid;
|
||||
TOKEN_PRIVILEGES tpPrevious;
|
||||
DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
|
||||
|
||||
if (!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;
|
||||
|
||||
// first pass. get current privilege setting
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Luid = luid;
|
||||
tp.Privileges[0].Attributes = 0;
|
||||
|
||||
AdjustTokenPrivileges(
|
||||
hToken,
|
||||
FALSE,
|
||||
&tp,
|
||||
sizeof(TOKEN_PRIVILEGES),
|
||||
&tpPrevious,
|
||||
&cbPrevious
|
||||
);
|
||||
|
||||
if (GetLastError() != ERROR_SUCCESS) return FALSE;
|
||||
|
||||
// second pass. set privilege based on previous setting
|
||||
tpPrevious.PrivilegeCount = 1;
|
||||
tpPrevious.Privileges[0].Luid = luid;
|
||||
|
||||
if (bEnablePrivilege)
|
||||
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
|
||||
else
|
||||
tpPrevious.Privileges[0].Attributes ^=
|
||||
(SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes);
|
||||
|
||||
AdjustTokenPrivileges(
|
||||
hToken,
|
||||
FALSE,
|
||||
&tpPrevious,
|
||||
cbPrevious,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (GetLastError() != ERROR_SUCCESS) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_set_se_debug()
|
||||
{
|
||||
HANDLE hToken;
|
||||
if (! OpenThreadToken(GetCurrentThread(),
|
||||
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
||||
FALSE,
|
||||
&hToken)
|
||||
) {
|
||||
if (GetLastError() == ERROR_NO_TOKEN) {
|
||||
if (!ImpersonateSelf(SecurityImpersonation)) {
|
||||
CloseHandle(hToken);
|
||||
return 0;
|
||||
}
|
||||
if (!OpenThreadToken(GetCurrentThread(),
|
||||
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
||||
FALSE,
|
||||
&hToken)
|
||||
) {
|
||||
RevertToSelf();
|
||||
CloseHandle(hToken);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// enable SeDebugPrivilege (open any process)
|
||||
if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, TRUE)) {
|
||||
RevertToSelf();
|
||||
CloseHandle(hToken);
|
||||
return 0;
|
||||
}
|
||||
|
||||
RevertToSelf();
|
||||
CloseHandle(hToken);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_unset_se_debug()
|
||||
{
|
||||
HANDLE hToken;
|
||||
if (! OpenThreadToken(GetCurrentThread(),
|
||||
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
||||
FALSE,
|
||||
&hToken)
|
||||
) {
|
||||
if (GetLastError() == ERROR_NO_TOKEN) {
|
||||
if (! ImpersonateSelf(SecurityImpersonation))
|
||||
return 0;
|
||||
if (!OpenThreadToken(GetCurrentThread(),
|
||||
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
||||
FALSE,
|
||||
&hToken))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now disable SeDebug
|
||||
if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE))
|
||||
return 0;
|
||||
|
||||
CloseHandle(hToken);
|
||||
return 1;
|
||||
}
|
||||
17
python/psutil/psutil/arch/windows/security.h
Normal file
17
python/psutil/psutil/arch/windows/security.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Security related functions for Windows platform (Set privileges such as
|
||||
* SeDebug), as well as security helper functions.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
BOOL psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege);
|
||||
HANDLE psutil_token_from_handle(HANDLE hProcess);
|
||||
int psutil_has_system_privilege(HANDLE hProcess);
|
||||
int psutil_set_se_debug();
|
||||
int psutil_unset_se_debug();
|
||||
|
||||
5
python/psutil/setup.cfg
Normal file
5
python/psutil/setup.cfg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
||||
206
python/psutil/setup.py
Normal file
206
python/psutil/setup.py
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009 Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""psutil is a cross-platform library for retrieving information on
|
||||
running processes and system utilization (CPU, memory, disks, network)
|
||||
in Python.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
try:
|
||||
from setuptools import setup, Extension
|
||||
except ImportError:
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
|
||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
def get_version():
|
||||
INIT = os.path.join(HERE, 'psutil/__init__.py')
|
||||
with open(INIT, 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith('__version__'):
|
||||
ret = eval(line.strip().split(' = ')[1])
|
||||
assert ret.count('.') == 2, ret
|
||||
for num in ret.split('.'):
|
||||
assert num.isdigit(), ret
|
||||
return ret
|
||||
else:
|
||||
raise ValueError("couldn't find version string")
|
||||
|
||||
|
||||
def get_description():
|
||||
README = os.path.join(HERE, 'README.rst')
|
||||
with open(README, 'r') as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
VERSION = get_version()
|
||||
VERSION_MACRO = ('PSUTIL_VERSION', int(VERSION.replace('.', '')))
|
||||
|
||||
|
||||
# POSIX
|
||||
if os.name == 'posix':
|
||||
libraries = []
|
||||
if sys.platform.startswith("sunos"):
|
||||
libraries.append('socket')
|
||||
|
||||
posix_extension = Extension(
|
||||
'psutil._psutil_posix',
|
||||
sources=['psutil/_psutil_posix.c'],
|
||||
libraries=libraries,
|
||||
)
|
||||
# Windows
|
||||
if sys.platform.startswith("win32"):
|
||||
|
||||
def get_winver():
|
||||
maj, min = sys.getwindowsversion()[0:2]
|
||||
return '0x0%s' % ((maj * 100) + min)
|
||||
|
||||
extensions = [Extension(
|
||||
'psutil._psutil_windows',
|
||||
sources=[
|
||||
'psutil/_psutil_windows.c',
|
||||
'psutil/_psutil_common.c',
|
||||
'psutil/arch/windows/process_info.c',
|
||||
'psutil/arch/windows/process_handles.c',
|
||||
'psutil/arch/windows/security.c',
|
||||
'psutil/arch/windows/inet_ntop.c',
|
||||
],
|
||||
define_macros=[
|
||||
VERSION_MACRO,
|
||||
# be nice to mingw, see:
|
||||
# http://www.mingw.org/wiki/Use_more_recent_defined_functions
|
||||
('_WIN32_WINNT', get_winver()),
|
||||
('_AVAIL_WINVER_', get_winver()),
|
||||
('_CRT_SECURE_NO_WARNINGS', None),
|
||||
# see: https://github.com/giampaolo/psutil/issues/348
|
||||
('PSAPI_VERSION', 1),
|
||||
],
|
||||
libraries=[
|
||||
"psapi", "kernel32", "advapi32", "shell32", "netapi32", "iphlpapi",
|
||||
"wtsapi32", "ws2_32",
|
||||
],
|
||||
# extra_compile_args=["/Z7"],
|
||||
# extra_link_args=["/DEBUG"]
|
||||
)]
|
||||
# OS X
|
||||
elif sys.platform.startswith("darwin"):
|
||||
extensions = [Extension(
|
||||
'psutil._psutil_osx',
|
||||
sources=[
|
||||
'psutil/_psutil_osx.c',
|
||||
'psutil/_psutil_common.c',
|
||||
'psutil/arch/osx/process_info.c'
|
||||
],
|
||||
define_macros=[VERSION_MACRO],
|
||||
extra_link_args=[
|
||||
'-framework', 'CoreFoundation', '-framework', 'IOKit'
|
||||
],
|
||||
),
|
||||
posix_extension,
|
||||
]
|
||||
# FreeBSD
|
||||
elif sys.platform.startswith("freebsd"):
|
||||
extensions = [Extension(
|
||||
'psutil._psutil_bsd',
|
||||
sources=[
|
||||
'psutil/_psutil_bsd.c',
|
||||
'psutil/_psutil_common.c',
|
||||
'psutil/arch/bsd/process_info.c'
|
||||
],
|
||||
define_macros=[VERSION_MACRO],
|
||||
libraries=["devstat"]),
|
||||
posix_extension,
|
||||
]
|
||||
# Linux
|
||||
elif sys.platform.startswith("linux"):
|
||||
extensions = [Extension(
|
||||
'psutil._psutil_linux',
|
||||
sources=['psutil/_psutil_linux.c'],
|
||||
define_macros=[VERSION_MACRO]),
|
||||
posix_extension,
|
||||
]
|
||||
# Solaris
|
||||
elif sys.platform.lower().startswith('sunos'):
|
||||
extensions = [Extension(
|
||||
'psutil._psutil_sunos',
|
||||
sources=['psutil/_psutil_sunos.c'],
|
||||
define_macros=[VERSION_MACRO],
|
||||
libraries=['kstat', 'nsl', 'socket']),
|
||||
posix_extension,
|
||||
]
|
||||
else:
|
||||
sys.exit('platform %s is not supported' % sys.platform)
|
||||
|
||||
|
||||
def main():
|
||||
setup_args = dict(
|
||||
name='psutil',
|
||||
version=VERSION,
|
||||
description=__doc__.replace('\n', '').strip(),
|
||||
long_description=get_description(),
|
||||
keywords=[
|
||||
'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', 'tty',
|
||||
'ionice', 'uptime', 'taskmgr', 'process', 'df', 'iotop', 'iostat',
|
||||
'ifconfig', 'taskset', 'who', 'pidof', 'pmap', 'smem', 'pstree',
|
||||
'monitoring', 'ulimit', 'prlimit',
|
||||
],
|
||||
author='Giampaolo Rodola',
|
||||
author_email='g.rodola <at> gmail <dot> com',
|
||||
url='https://github.com/giampaolo/psutil',
|
||||
platforms='Platform Independent',
|
||||
license='BSD',
|
||||
packages=['psutil'],
|
||||
# see: python setup.py register --list-classifiers
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Console',
|
||||
'Environment :: Win32 (MS Windows)',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Information Technology',
|
||||
'Intended Audience :: System Administrators',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Operating System :: MacOS :: MacOS X',
|
||||
'Operating System :: Microsoft :: Windows :: Windows NT/2000',
|
||||
'Operating System :: Microsoft',
|
||||
'Operating System :: OS Independent',
|
||||
'Operating System :: POSIX :: BSD :: FreeBSD',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Operating System :: POSIX :: SunOS/Solaris',
|
||||
'Operating System :: POSIX',
|
||||
'Programming Language :: C',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.0',
|
||||
'Programming Language :: Python :: 3.1',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
'Programming Language :: Python',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Software Development :: Libraries',
|
||||
'Topic :: System :: Benchmark',
|
||||
'Topic :: System :: Hardware',
|
||||
'Topic :: System :: Monitoring',
|
||||
'Topic :: System :: Networking :: Monitoring',
|
||||
'Topic :: System :: Networking',
|
||||
'Topic :: System :: Systems Administration',
|
||||
'Topic :: Utilities',
|
||||
],
|
||||
)
|
||||
if extensions is not None:
|
||||
setup_args["ext_modules"] = extensions
|
||||
setup(**setup_args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
21
python/psutil/test/README.rst
Normal file
21
python/psutil/test/README.rst
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
- The recommended way to run tests (also on Windows) is to cd into parent
|
||||
directory and run ``make test``
|
||||
|
||||
- Dependencies for running tests:
|
||||
- python 2.6: ipaddress, mock, unittest2
|
||||
- python 2.7: ipaddress, mock
|
||||
- python 3.2: ipaddress, mock
|
||||
- python 3.3: ipaddress
|
||||
- python >= 3.4: no deps required
|
||||
|
||||
- The main test script is ``test_psutil.py``, which also imports platform-specific
|
||||
``_*.py`` scripts (which should be ignored).
|
||||
|
||||
- ``test_memory_leaks.py`` looks for memory leaks into C extension modules and must
|
||||
be run separately with ``make test-memleaks``.
|
||||
|
||||
- To run tests on all supported Python version install tox (pip install tox)
|
||||
then run ``tox``.
|
||||
|
||||
- Every time a commit is pushed tests are automatically run on Travis:
|
||||
https://travis-ci.org/giampaolo/psutil/
|
||||
252
python/psutil/test/_bsd.py
Normal file
252
python/psutil/test/_bsd.py
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# TODO: add test for comparing connections with 'sockstat' cmd
|
||||
|
||||
"""BSD specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
import psutil
|
||||
|
||||
from psutil._compat import PY3
|
||||
from test_psutil import (TOLERANCE, BSD, sh, get_test_subprocess, which,
|
||||
retry_before_failing, reap_children, unittest)
|
||||
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
if os.getuid() == 0: # muse requires root privileges
|
||||
MUSE_AVAILABLE = which('muse')
|
||||
else:
|
||||
MUSE_AVAILABLE = False
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
"""Expects a sysctl command with an argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
result = sh("sysctl " + cmdline)
|
||||
result = result[result.find(": ") + 2:]
|
||||
try:
|
||||
return int(result)
|
||||
except ValueError:
|
||||
return result
|
||||
|
||||
|
||||
def muse(field):
|
||||
"""Thin wrapper around 'muse' cmdline utility."""
|
||||
out = sh('muse')
|
||||
for line in out.split('\n'):
|
||||
if line.startswith(field):
|
||||
break
|
||||
else:
|
||||
raise ValueError("line not found")
|
||||
return int(line.split()[1])
|
||||
|
||||
|
||||
@unittest.skipUnless(BSD, "not a BSD system")
|
||||
class BSDSpecificTestCase(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_boot_time(self):
|
||||
s = sysctl('sysctl kern.boottime')
|
||||
s = s[s.find(" sec = ") + 7:]
|
||||
s = s[:s.find(',')]
|
||||
btime = int(s)
|
||||
self.assertEqual(btime, psutil.boot_time())
|
||||
|
||||
def test_process_create_time(self):
|
||||
cmdline = "ps -o lstart -p %s" % self.pid
|
||||
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0]
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
start_ps = output.replace('STARTED', '').strip()
|
||||
start_psutil = psutil.Process(self.pid).create_time()
|
||||
start_psutil = time.strftime("%a %b %e %H:%M:%S %Y",
|
||||
time.localtime(start_psutil))
|
||||
self.assertEqual(start_ps, start_psutil)
|
||||
|
||||
def test_disks(self):
|
||||
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||
# against "df -a"
|
||||
def df(path):
|
||||
out = sh('df -k "%s"' % path).strip()
|
||||
lines = out.split('\n')
|
||||
lines.pop(0)
|
||||
line = lines.pop(0)
|
||||
dev, total, used, free = line.split()[:4]
|
||||
if dev == 'none':
|
||||
dev = ''
|
||||
total = int(total) * 1024
|
||||
used = int(used) * 1024
|
||||
free = int(free) * 1024
|
||||
return dev, total, used, free
|
||||
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
dev, total, used, free = df(part.mountpoint)
|
||||
self.assertEqual(part.device, dev)
|
||||
self.assertEqual(usage.total, total)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.free, free))
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.used, used))
|
||||
|
||||
@retry_before_failing()
|
||||
def test_memory_maps(self):
|
||||
out = sh('procstat -v %s' % self.pid)
|
||||
maps = psutil.Process(self.pid).memory_maps(grouped=False)
|
||||
lines = out.split('\n')[1:]
|
||||
while lines:
|
||||
line = lines.pop()
|
||||
fields = line.split()
|
||||
_, start, stop, perms, res = fields[:5]
|
||||
map = maps.pop()
|
||||
self.assertEqual("%s-%s" % (start, stop), map.addr)
|
||||
self.assertEqual(int(res), map.rss)
|
||||
if not map.path.startswith('['):
|
||||
self.assertEqual(fields[10], map.path)
|
||||
|
||||
def test_exe(self):
|
||||
out = sh('procstat -b %s' % self.pid)
|
||||
self.assertEqual(psutil.Process(self.pid).exe(),
|
||||
out.split('\n')[1].split()[-1])
|
||||
|
||||
def test_cmdline(self):
|
||||
out = sh('procstat -c %s' % self.pid)
|
||||
self.assertEqual(' '.join(psutil.Process(self.pid).cmdline()),
|
||||
' '.join(out.split('\n')[1].split()[2:]))
|
||||
|
||||
def test_uids_gids(self):
|
||||
out = sh('procstat -s %s' % self.pid)
|
||||
euid, ruid, suid, egid, rgid, sgid = out.split('\n')[1].split()[2:8]
|
||||
p = psutil.Process(self.pid)
|
||||
uids = p.uids()
|
||||
gids = p.gids()
|
||||
self.assertEqual(uids.real, int(ruid))
|
||||
self.assertEqual(uids.effective, int(euid))
|
||||
self.assertEqual(uids.saved, int(suid))
|
||||
self.assertEqual(gids.real, int(rgid))
|
||||
self.assertEqual(gids.effective, int(egid))
|
||||
self.assertEqual(gids.saved, int(sgid))
|
||||
|
||||
# --- virtual_memory(); tests against sysctl
|
||||
|
||||
def test_vmem_total(self):
|
||||
syst = sysctl("sysctl vm.stats.vm.v_page_count") * PAGESIZE
|
||||
self.assertEqual(psutil.virtual_memory().total, syst)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_active(self):
|
||||
syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().active, syst,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_inactive(self):
|
||||
syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().inactive, syst,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_wired(self):
|
||||
syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().wired, syst,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_cached(self):
|
||||
syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().cached, syst,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_free(self):
|
||||
syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().free, syst,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_buffers(self):
|
||||
syst = sysctl("vfs.bufspace")
|
||||
self.assertAlmostEqual(psutil.virtual_memory().buffers, syst,
|
||||
delta=TOLERANCE)
|
||||
|
||||
def test_cpu_count_logical(self):
|
||||
syst = sysctl("hw.ncpu")
|
||||
self.assertEqual(psutil.cpu_count(logical=True), syst)
|
||||
|
||||
# --- virtual_memory(); tests against muse
|
||||
|
||||
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
|
||||
def test_total(self):
|
||||
num = muse('Total')
|
||||
self.assertEqual(psutil.virtual_memory().total, num)
|
||||
|
||||
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
|
||||
@retry_before_failing()
|
||||
def test_active(self):
|
||||
num = muse('Active')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().active, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
|
||||
@retry_before_failing()
|
||||
def test_inactive(self):
|
||||
num = muse('Inactive')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().inactive, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
|
||||
@retry_before_failing()
|
||||
def test_wired(self):
|
||||
num = muse('Wired')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().wired, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
|
||||
@retry_before_failing()
|
||||
def test_cached(self):
|
||||
num = muse('Cache')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().cached, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
|
||||
@retry_before_failing()
|
||||
def test_free(self):
|
||||
num = muse('Free')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().free, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
|
||||
@retry_before_failing()
|
||||
def test_buffers(self):
|
||||
num = muse('Buffer')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().buffers, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
|
||||
def main():
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase))
|
||||
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
return result.wasSuccessful()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not main():
|
||||
sys.exit(1)
|
||||
473
python/psutil/test/_linux.py
Normal file
473
python/psutil/test/_linux.py
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Linux specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
from __future__ import division
|
||||
import contextlib
|
||||
import errno
|
||||
import fcntl
|
||||
import io
|
||||
import os
|
||||
import pprint
|
||||
import re
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import warnings
|
||||
|
||||
try:
|
||||
from unittest import mock # py3
|
||||
except ImportError:
|
||||
import mock # requires "pip install mock"
|
||||
|
||||
from test_psutil import POSIX, TOLERANCE, TRAVIS, LINUX
|
||||
from test_psutil import (skip_on_not_implemented, sh, get_test_subprocess,
|
||||
retry_before_failing, get_kernel_version, unittest,
|
||||
which, call_until)
|
||||
|
||||
import psutil
|
||||
import psutil._pslinux
|
||||
from psutil._compat import PY3, u
|
||||
|
||||
|
||||
SIOCGIFADDR = 0x8915
|
||||
SIOCGIFCONF = 0x8912
|
||||
SIOCGIFHWADDR = 0x8927
|
||||
|
||||
|
||||
def get_ipv4_address(ifname):
|
||||
ifname = ifname[:15]
|
||||
if PY3:
|
||||
ifname = bytes(ifname, 'ascii')
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
with contextlib.closing(s):
|
||||
return socket.inet_ntoa(
|
||||
fcntl.ioctl(s.fileno(),
|
||||
SIOCGIFADDR,
|
||||
struct.pack('256s', ifname))[20:24])
|
||||
|
||||
|
||||
def get_mac_address(ifname):
|
||||
ifname = ifname[:15]
|
||||
if PY3:
|
||||
ifname = bytes(ifname, 'ascii')
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
with contextlib.closing(s):
|
||||
info = fcntl.ioctl(
|
||||
s.fileno(), SIOCGIFHWADDR, struct.pack('256s', ifname))
|
||||
if PY3:
|
||||
def ord(x):
|
||||
return x
|
||||
else:
|
||||
import __builtin__
|
||||
ord = __builtin__.ord
|
||||
return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
|
||||
|
||||
|
||||
@unittest.skipUnless(LINUX, "not a Linux system")
|
||||
class LinuxSpecificTestCase(unittest.TestCase):
|
||||
|
||||
@unittest.skipIf(
|
||||
POSIX and not hasattr(os, 'statvfs'),
|
||||
reason="os.statvfs() function not available on this platform")
|
||||
@skip_on_not_implemented()
|
||||
def test_disks(self):
|
||||
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||
# against "df -a"
|
||||
def df(path):
|
||||
out = sh('df -P -B 1 "%s"' % path).strip()
|
||||
lines = out.split('\n')
|
||||
lines.pop(0)
|
||||
line = lines.pop(0)
|
||||
dev, total, used, free = line.split()[:4]
|
||||
if dev == 'none':
|
||||
dev = ''
|
||||
total, used, free = int(total), int(used), int(free)
|
||||
return dev, total, used, free
|
||||
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
dev, total, used, free = df(part.mountpoint)
|
||||
self.assertEqual(part.device, dev)
|
||||
self.assertEqual(usage.total, total)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.free, free))
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.used, used))
|
||||
|
||||
def test_memory_maps(self):
|
||||
sproc = get_test_subprocess()
|
||||
time.sleep(1)
|
||||
p = psutil.Process(sproc.pid)
|
||||
maps = p.memory_maps(grouped=False)
|
||||
pmap = sh('pmap -x %s' % p.pid).split('\n')
|
||||
# get rid of header
|
||||
del pmap[0]
|
||||
del pmap[0]
|
||||
while maps and pmap:
|
||||
this = maps.pop(0)
|
||||
other = pmap.pop(0)
|
||||
addr, _, rss, dirty, mode, path = other.split(None, 5)
|
||||
if not path.startswith('[') and not path.endswith(']'):
|
||||
self.assertEqual(path, os.path.basename(this.path))
|
||||
self.assertEqual(int(rss) * 1024, this.rss)
|
||||
# test only rwx chars, ignore 's' and 'p'
|
||||
self.assertEqual(mode[:3], this.perms[:3])
|
||||
|
||||
def test_vmem_total(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
total = int(lines[0].split()[1]) * 1024
|
||||
self.assertEqual(total, psutil.virtual_memory().total)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_used(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
used = int(lines[0].split()[2]) * 1024
|
||||
self.assertAlmostEqual(used, psutil.virtual_memory().used,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_free(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
free = int(lines[0].split()[3]) * 1024
|
||||
self.assertAlmostEqual(free, psutil.virtual_memory().free,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_buffers(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
buffers = int(lines[0].split()[5]) * 1024
|
||||
self.assertAlmostEqual(buffers, psutil.virtual_memory().buffers,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_cached(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
cached = int(lines[0].split()[6]) * 1024
|
||||
self.assertAlmostEqual(cached, psutil.virtual_memory().cached,
|
||||
delta=TOLERANCE)
|
||||
|
||||
def test_swapmem_total(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
total = int(lines[2].split()[1]) * 1024
|
||||
self.assertEqual(total, psutil.swap_memory().total)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_swapmem_used(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
used = int(lines[2].split()[2]) * 1024
|
||||
self.assertAlmostEqual(used, psutil.swap_memory().used,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_swapmem_free(self):
|
||||
lines = sh('free').split('\n')[1:]
|
||||
free = int(lines[2].split()[3]) * 1024
|
||||
self.assertAlmostEqual(free, psutil.swap_memory().free,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@unittest.skipIf(TRAVIS, "unknown failure on travis")
|
||||
def test_cpu_times(self):
|
||||
fields = psutil.cpu_times()._fields
|
||||
kernel_ver = re.findall('\d+\.\d+\.\d+', os.uname()[2])[0]
|
||||
kernel_ver_info = tuple(map(int, kernel_ver.split('.')))
|
||||
if kernel_ver_info >= (2, 6, 11):
|
||||
self.assertIn('steal', fields)
|
||||
else:
|
||||
self.assertNotIn('steal', fields)
|
||||
if kernel_ver_info >= (2, 6, 24):
|
||||
self.assertIn('guest', fields)
|
||||
else:
|
||||
self.assertNotIn('guest', fields)
|
||||
if kernel_ver_info >= (3, 2, 0):
|
||||
self.assertIn('guest_nice', fields)
|
||||
else:
|
||||
self.assertNotIn('guest_nice', fields)
|
||||
|
||||
def test_net_if_addrs_ips(self):
|
||||
for name, addrs in psutil.net_if_addrs().items():
|
||||
for addr in addrs:
|
||||
if addr.family == psutil.AF_LINK:
|
||||
self.assertEqual(addr.address, get_mac_address(name))
|
||||
elif addr.family == socket.AF_INET:
|
||||
self.assertEqual(addr.address, get_ipv4_address(name))
|
||||
# TODO: test for AF_INET6 family
|
||||
|
||||
@unittest.skipUnless(which('ip'), "'ip' utility not available")
|
||||
@unittest.skipIf(TRAVIS, "skipped on Travis")
|
||||
def test_net_if_names(self):
|
||||
out = sh("ip addr").strip()
|
||||
nics = psutil.net_if_addrs()
|
||||
found = 0
|
||||
for line in out.split('\n'):
|
||||
line = line.strip()
|
||||
if re.search("^\d+:", line):
|
||||
found += 1
|
||||
name = line.split(':')[1].strip()
|
||||
self.assertIn(name, nics.keys())
|
||||
self.assertEqual(len(nics), found, msg="%s\n---\n%s" % (
|
||||
pprint.pformat(nics), out))
|
||||
|
||||
@unittest.skipUnless(which("nproc"), "nproc utility not available")
|
||||
def test_cpu_count_logical_w_nproc(self):
|
||||
num = int(sh("nproc --all"))
|
||||
self.assertEqual(psutil.cpu_count(logical=True), num)
|
||||
|
||||
@unittest.skipUnless(which("lscpu"), "lscpu utility not available")
|
||||
def test_cpu_count_logical_w_lscpu(self):
|
||||
out = sh("lscpu -p")
|
||||
num = len([x for x in out.split('\n') if not x.startswith('#')])
|
||||
self.assertEqual(psutil.cpu_count(logical=True), num)
|
||||
|
||||
# --- mocked tests
|
||||
|
||||
def test_virtual_memory_mocked_warnings(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
with warnings.catch_warnings(record=True) as ws:
|
||||
warnings.simplefilter("always")
|
||||
ret = psutil._pslinux.virtual_memory()
|
||||
assert m.called
|
||||
self.assertEqual(len(ws), 1)
|
||||
w = ws[0]
|
||||
self.assertTrue(w.filename.endswith('psutil/_pslinux.py'))
|
||||
self.assertIn(
|
||||
"'cached', 'active' and 'inactive' memory stats couldn't "
|
||||
"be determined", str(w.message))
|
||||
self.assertEqual(ret.cached, 0)
|
||||
self.assertEqual(ret.active, 0)
|
||||
self.assertEqual(ret.inactive, 0)
|
||||
|
||||
def test_swap_memory_mocked_warnings(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
with warnings.catch_warnings(record=True) as ws:
|
||||
warnings.simplefilter("always")
|
||||
ret = psutil._pslinux.swap_memory()
|
||||
assert m.called
|
||||
self.assertEqual(len(ws), 1)
|
||||
w = ws[0]
|
||||
self.assertTrue(w.filename.endswith('psutil/_pslinux.py'))
|
||||
self.assertIn(
|
||||
"'sin' and 'sout' swap memory stats couldn't "
|
||||
"be determined", str(w.message))
|
||||
self.assertEqual(ret.sin, 0)
|
||||
self.assertEqual(ret.sout, 0)
|
||||
|
||||
def test_cpu_count_logical_mocked(self):
|
||||
import psutil._pslinux
|
||||
original = psutil._pslinux.cpu_count_logical()
|
||||
# Here we want to mock os.sysconf("SC_NPROCESSORS_ONLN") in
|
||||
# order to cause the parsing of /proc/cpuinfo and /proc/stat.
|
||||
with mock.patch(
|
||||
'psutil._pslinux.os.sysconf', side_effect=ValueError) as m:
|
||||
self.assertEqual(psutil._pslinux.cpu_count_logical(), original)
|
||||
assert m.called
|
||||
|
||||
# Let's have open() return emtpy data and make sure None is
|
||||
# returned ('cause we mimick os.cpu_count()).
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertIsNone(psutil._pslinux.cpu_count_logical())
|
||||
self.assertEqual(m.call_count, 2)
|
||||
# /proc/stat should be the last one
|
||||
self.assertEqual(m.call_args[0][0], '/proc/stat')
|
||||
|
||||
# Let's push this a bit further and make sure /proc/cpuinfo
|
||||
# parsing works as expected.
|
||||
with open('/proc/cpuinfo', 'rb') as f:
|
||||
cpuinfo_data = f.read()
|
||||
fake_file = io.BytesIO(cpuinfo_data)
|
||||
with mock.patch('psutil._pslinux.open',
|
||||
return_value=fake_file, create=True) as m:
|
||||
self.assertEqual(psutil._pslinux.cpu_count_logical(), original)
|
||||
|
||||
def test_cpu_count_physical_mocked(self):
|
||||
# Have open() return emtpy data and make sure None is returned
|
||||
# ('cause we want to mimick os.cpu_count())
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertIsNone(psutil._pslinux.cpu_count_physical())
|
||||
assert m.called
|
||||
|
||||
def test_proc_open_files_file_gone(self):
|
||||
# simulates a file which gets deleted during open_files()
|
||||
# execution
|
||||
p = psutil.Process()
|
||||
files = p.open_files()
|
||||
with tempfile.NamedTemporaryFile():
|
||||
# give the kernel some time to see the new file
|
||||
call_until(p.open_files, "len(ret) != %i" % len(files))
|
||||
with mock.patch('psutil._pslinux.os.readlink',
|
||||
side_effect=OSError(errno.ENOENT, "")) as m:
|
||||
files = p.open_files()
|
||||
assert not files
|
||||
assert m.called
|
||||
# also simulate the case where os.readlink() returns EINVAL
|
||||
# in which case psutil is supposed to 'continue'
|
||||
with mock.patch('psutil._pslinux.os.readlink',
|
||||
side_effect=OSError(errno.EINVAL, "")) as m:
|
||||
self.assertEqual(p.open_files(), [])
|
||||
assert m.called
|
||||
|
||||
def test_proc_terminal_mocked(self):
|
||||
with mock.patch('psutil._pslinux._psposix._get_terminal_map',
|
||||
return_value={}) as m:
|
||||
self.assertIsNone(psutil._pslinux.Process(os.getpid()).terminal())
|
||||
assert m.called
|
||||
|
||||
def test_proc_num_ctx_switches_mocked(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
psutil._pslinux.Process(os.getpid()).num_ctx_switches)
|
||||
assert m.called
|
||||
|
||||
def test_proc_num_threads_mocked(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
psutil._pslinux.Process(os.getpid()).num_threads)
|
||||
assert m.called
|
||||
|
||||
def test_proc_ppid_mocked(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
psutil._pslinux.Process(os.getpid()).ppid)
|
||||
assert m.called
|
||||
|
||||
def test_proc_uids_mocked(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
psutil._pslinux.Process(os.getpid()).uids)
|
||||
assert m.called
|
||||
|
||||
def test_proc_gids_mocked(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
psutil._pslinux.Process(os.getpid()).gids)
|
||||
assert m.called
|
||||
|
||||
def test_proc_cmdline_mocked(self):
|
||||
# see: https://github.com/giampaolo/psutil/issues/639
|
||||
p = psutil.Process()
|
||||
fake_file = io.StringIO(u('foo\x00bar\x00'))
|
||||
with mock.patch('psutil._pslinux.open',
|
||||
return_value=fake_file, create=True) as m:
|
||||
p.cmdline() == ['foo', 'bar']
|
||||
assert m.called
|
||||
fake_file = io.StringIO(u('foo\x00bar\x00\x00'))
|
||||
with mock.patch('psutil._pslinux.open',
|
||||
return_value=fake_file, create=True) as m:
|
||||
p.cmdline() == ['foo', 'bar', '']
|
||||
assert m.called
|
||||
|
||||
def test_proc_io_counters_mocked(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
psutil._pslinux.Process(os.getpid()).io_counters)
|
||||
assert m.called
|
||||
|
||||
def test_boot_time_mocked(self):
|
||||
with mock.patch('psutil._pslinux.open', create=True) as m:
|
||||
self.assertRaises(
|
||||
RuntimeError,
|
||||
psutil._pslinux.boot_time)
|
||||
assert m.called
|
||||
|
||||
def test_users_mocked(self):
|
||||
# Make sure ':0' and ':0.0' (returned by C ext) are converted
|
||||
# to 'localhost'.
|
||||
with mock.patch('psutil._pslinux.cext.users',
|
||||
return_value=[('giampaolo', 'pts/2', ':0',
|
||||
1436573184.0, True)]) as m:
|
||||
self.assertEqual(psutil.users()[0].host, 'localhost')
|
||||
assert m.called
|
||||
with mock.patch('psutil._pslinux.cext.users',
|
||||
return_value=[('giampaolo', 'pts/2', ':0.0',
|
||||
1436573184.0, True)]) as m:
|
||||
self.assertEqual(psutil.users()[0].host, 'localhost')
|
||||
assert m.called
|
||||
# ...otherwise it should be returned as-is
|
||||
with mock.patch('psutil._pslinux.cext.users',
|
||||
return_value=[('giampaolo', 'pts/2', 'foo',
|
||||
1436573184.0, True)]) as m:
|
||||
self.assertEqual(psutil.users()[0].host, 'foo')
|
||||
assert m.called
|
||||
|
||||
def test_disk_partitions_mocked(self):
|
||||
# Test that ZFS partitions are returned.
|
||||
with open("/proc/filesystems", "r") as f:
|
||||
data = f.read()
|
||||
if 'zfs' in data:
|
||||
for part in psutil.disk_partitions():
|
||||
if part.fstype == 'zfs':
|
||||
break
|
||||
else:
|
||||
self.fail("couldn't find any ZFS partition")
|
||||
else:
|
||||
# No ZFS partitions on this system. Let's fake one.
|
||||
fake_file = io.StringIO(u("nodev\tzfs\n"))
|
||||
with mock.patch('psutil._pslinux.open',
|
||||
return_value=fake_file, create=True) as m1:
|
||||
with mock.patch(
|
||||
'psutil._pslinux.cext.disk_partitions',
|
||||
return_value=[('/dev/sdb3', '/', 'zfs', 'rw')]) as m2:
|
||||
ret = psutil.disk_partitions()
|
||||
assert m1.called
|
||||
assert m2.called
|
||||
assert ret
|
||||
self.assertEqual(ret[0].fstype, 'zfs')
|
||||
|
||||
# --- tests for specific kernel versions
|
||||
|
||||
@unittest.skipUnless(
|
||||
get_kernel_version() >= (2, 6, 36),
|
||||
"prlimit() not available on this Linux kernel version")
|
||||
def test_prlimit_availability(self):
|
||||
# prlimit() should be available starting from kernel 2.6.36
|
||||
p = psutil.Process(os.getpid())
|
||||
p.rlimit(psutil.RLIMIT_NOFILE)
|
||||
# if prlimit() is supported *at least* these constants should
|
||||
# be available
|
||||
self.assertTrue(hasattr(psutil, "RLIM_INFINITY"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_AS"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_CORE"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_CPU"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_DATA"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_FSIZE"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_LOCKS"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_MEMLOCK"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_NOFILE"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_NPROC"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_RSS"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_STACK"))
|
||||
|
||||
@unittest.skipUnless(
|
||||
get_kernel_version() >= (3, 0),
|
||||
"prlimit constants not available on this Linux kernel version")
|
||||
def test_resource_consts_kernel_v(self):
|
||||
# more recent constants
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_MSGQUEUE"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_NICE"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_RTPRIO"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_RTTIME"))
|
||||
self.assertTrue(hasattr(psutil, "RLIMIT_SIGPENDING"))
|
||||
|
||||
|
||||
def main():
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(LinuxSpecificTestCase))
|
||||
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
return result.wasSuccessful()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not main():
|
||||
sys.exit(1)
|
||||
160
python/psutil/test/_osx.py
Normal file
160
python/psutil/test/_osx.py
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""OSX specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
import psutil
|
||||
|
||||
from psutil._compat import PY3
|
||||
from test_psutil import (TOLERANCE, OSX, sh, get_test_subprocess,
|
||||
reap_children, retry_before_failing, unittest)
|
||||
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
"""Expects a sysctl command with an argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
|
||||
result = p.communicate()[0].strip().split()[1]
|
||||
if PY3:
|
||||
result = str(result, sys.stdout.encoding)
|
||||
try:
|
||||
return int(result)
|
||||
except ValueError:
|
||||
return result
|
||||
|
||||
|
||||
def vm_stat(field):
|
||||
"""Wrapper around 'vm_stat' cmdline utility."""
|
||||
out = sh('vm_stat')
|
||||
for line in out.split('\n'):
|
||||
if field in line:
|
||||
break
|
||||
else:
|
||||
raise ValueError("line not found")
|
||||
return int(re.search('\d+', line).group(0)) * PAGESIZE
|
||||
|
||||
|
||||
@unittest.skipUnless(OSX, "not an OSX system")
|
||||
class OSXSpecificTestCase(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_process_create_time(self):
|
||||
cmdline = "ps -o lstart -p %s" % self.pid
|
||||
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0]
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
start_ps = output.replace('STARTED', '').strip()
|
||||
start_psutil = psutil.Process(self.pid).create_time()
|
||||
start_psutil = time.strftime("%a %b %e %H:%M:%S %Y",
|
||||
time.localtime(start_psutil))
|
||||
self.assertEqual(start_ps, start_psutil)
|
||||
|
||||
def test_disks(self):
|
||||
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||
# against "df -a"
|
||||
def df(path):
|
||||
out = sh('df -k "%s"' % path).strip()
|
||||
lines = out.split('\n')
|
||||
lines.pop(0)
|
||||
line = lines.pop(0)
|
||||
dev, total, used, free = line.split()[:4]
|
||||
if dev == 'none':
|
||||
dev = ''
|
||||
total = int(total) * 1024
|
||||
used = int(used) * 1024
|
||||
free = int(free) * 1024
|
||||
return dev, total, used, free
|
||||
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
dev, total, used, free = df(part.mountpoint)
|
||||
self.assertEqual(part.device, dev)
|
||||
self.assertEqual(usage.total, total)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % usage.free, free)
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % usage.used, used)
|
||||
|
||||
# --- virtual mem
|
||||
|
||||
def test_vmem_total(self):
|
||||
sysctl_hwphymem = sysctl('sysctl hw.memsize')
|
||||
self.assertEqual(sysctl_hwphymem, psutil.virtual_memory().total)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_free(self):
|
||||
num = vm_stat("free")
|
||||
self.assertAlmostEqual(psutil.virtual_memory().free, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_active(self):
|
||||
num = vm_stat("active")
|
||||
self.assertAlmostEqual(psutil.virtual_memory().active, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_inactive(self):
|
||||
num = vm_stat("inactive")
|
||||
self.assertAlmostEqual(psutil.virtual_memory().inactive, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_vmem_wired(self):
|
||||
num = vm_stat("wired")
|
||||
self.assertAlmostEqual(psutil.virtual_memory().wired, num,
|
||||
delta=TOLERANCE)
|
||||
|
||||
# --- swap mem
|
||||
|
||||
def test_swapmem_sin(self):
|
||||
num = vm_stat("Pageins")
|
||||
self.assertEqual(psutil.swap_memory().sin, num)
|
||||
|
||||
def test_swapmem_sout(self):
|
||||
num = vm_stat("Pageouts")
|
||||
self.assertEqual(psutil.swap_memory().sout, num)
|
||||
|
||||
def test_swapmem_total(self):
|
||||
tot1 = psutil.swap_memory().total
|
||||
tot2 = 0
|
||||
# OSX uses multiple cache files:
|
||||
# http://en.wikipedia.org/wiki/Paging#OS_X
|
||||
for name in os.listdir("/var/vm/"):
|
||||
file = os.path.join("/var/vm", name)
|
||||
if os.path.isfile(file):
|
||||
tot2 += os.path.getsize(file)
|
||||
self.assertEqual(tot1, tot2)
|
||||
|
||||
|
||||
def main():
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(OSXSpecificTestCase))
|
||||
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
return result.wasSuccessful()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not main():
|
||||
sys.exit(1)
|
||||
258
python/psutil/test/_posix.py
Normal file
258
python/psutil/test/_posix.py
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""POSIX specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
import psutil
|
||||
|
||||
from psutil._compat import PY3, callable
|
||||
from test_psutil import LINUX, SUNOS, OSX, BSD, PYTHON, POSIX, TRAVIS
|
||||
from test_psutil import (get_test_subprocess, skip_on_access_denied,
|
||||
retry_before_failing, reap_children, sh, unittest,
|
||||
get_kernel_version, wait_for_pid)
|
||||
|
||||
|
||||
def ps(cmd):
|
||||
"""Expects a ps command with a -o argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
if not LINUX:
|
||||
cmd = cmd.replace(" --no-headers ", " ")
|
||||
if SUNOS:
|
||||
cmd = cmd.replace("-o command", "-o comm")
|
||||
cmd = cmd.replace("-o start", "-o stime")
|
||||
p = subprocess.Popen(cmd, shell=1, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].strip()
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
if not LINUX:
|
||||
output = output.split('\n')[1].strip()
|
||||
try:
|
||||
return int(output)
|
||||
except ValueError:
|
||||
return output
|
||||
|
||||
|
||||
@unittest.skipUnless(POSIX, "not a POSIX system")
|
||||
class PosixSpecificTestCase(unittest.TestCase):
|
||||
"""Compare psutil results against 'ps' command line utility."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess([PYTHON, "-E", "-O"],
|
||||
stdin=subprocess.PIPE).pid
|
||||
wait_for_pid(cls.pid)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
# for ps -o arguments see: http://unixhelp.ed.ac.uk/CGI/man-cgi?ps
|
||||
|
||||
def test_process_parent_pid(self):
|
||||
ppid_ps = ps("ps --no-headers -o ppid -p %s" % self.pid)
|
||||
ppid_psutil = psutil.Process(self.pid).ppid()
|
||||
self.assertEqual(ppid_ps, ppid_psutil)
|
||||
|
||||
def test_process_uid(self):
|
||||
uid_ps = ps("ps --no-headers -o uid -p %s" % self.pid)
|
||||
uid_psutil = psutil.Process(self.pid).uids().real
|
||||
self.assertEqual(uid_ps, uid_psutil)
|
||||
|
||||
def test_process_gid(self):
|
||||
gid_ps = ps("ps --no-headers -o rgid -p %s" % self.pid)
|
||||
gid_psutil = psutil.Process(self.pid).gids().real
|
||||
self.assertEqual(gid_ps, gid_psutil)
|
||||
|
||||
def test_process_username(self):
|
||||
username_ps = ps("ps --no-headers -o user -p %s" % self.pid)
|
||||
username_psutil = psutil.Process(self.pid).username()
|
||||
self.assertEqual(username_ps, username_psutil)
|
||||
|
||||
@skip_on_access_denied()
|
||||
@retry_before_failing()
|
||||
def test_process_rss_memory(self):
|
||||
# give python interpreter some time to properly initialize
|
||||
# so that the results are the same
|
||||
time.sleep(0.1)
|
||||
rss_ps = ps("ps --no-headers -o rss -p %s" % self.pid)
|
||||
rss_psutil = psutil.Process(self.pid).memory_info()[0] / 1024
|
||||
self.assertEqual(rss_ps, rss_psutil)
|
||||
|
||||
@skip_on_access_denied()
|
||||
@retry_before_failing()
|
||||
def test_process_vsz_memory(self):
|
||||
# give python interpreter some time to properly initialize
|
||||
# so that the results are the same
|
||||
time.sleep(0.1)
|
||||
vsz_ps = ps("ps --no-headers -o vsz -p %s" % self.pid)
|
||||
vsz_psutil = psutil.Process(self.pid).memory_info()[1] / 1024
|
||||
self.assertEqual(vsz_ps, vsz_psutil)
|
||||
|
||||
def test_process_name(self):
|
||||
# use command + arg since "comm" keyword not supported on all platforms
|
||||
name_ps = ps("ps --no-headers -o command -p %s" % (
|
||||
self.pid)).split(' ')[0]
|
||||
# remove path if there is any, from the command
|
||||
name_ps = os.path.basename(name_ps).lower()
|
||||
name_psutil = psutil.Process(self.pid).name().lower()
|
||||
self.assertEqual(name_ps, name_psutil)
|
||||
|
||||
@unittest.skipIf(OSX or BSD,
|
||||
'ps -o start not available')
|
||||
def test_process_create_time(self):
|
||||
time_ps = ps("ps --no-headers -o start -p %s" % self.pid).split(' ')[0]
|
||||
time_psutil = psutil.Process(self.pid).create_time()
|
||||
time_psutil_tstamp = datetime.datetime.fromtimestamp(
|
||||
time_psutil).strftime("%H:%M:%S")
|
||||
# sometimes ps shows the time rounded up instead of down, so we check
|
||||
# for both possible values
|
||||
round_time_psutil = round(time_psutil)
|
||||
round_time_psutil_tstamp = datetime.datetime.fromtimestamp(
|
||||
round_time_psutil).strftime("%H:%M:%S")
|
||||
self.assertIn(time_ps, [time_psutil_tstamp, round_time_psutil_tstamp])
|
||||
|
||||
def test_process_exe(self):
|
||||
ps_pathname = ps("ps --no-headers -o command -p %s" %
|
||||
self.pid).split(' ')[0]
|
||||
psutil_pathname = psutil.Process(self.pid).exe()
|
||||
try:
|
||||
self.assertEqual(ps_pathname, psutil_pathname)
|
||||
except AssertionError:
|
||||
# certain platforms such as BSD are more accurate returning:
|
||||
# "/usr/local/bin/python2.7"
|
||||
# ...instead of:
|
||||
# "/usr/local/bin/python"
|
||||
# We do not want to consider this difference in accuracy
|
||||
# an error.
|
||||
adjusted_ps_pathname = ps_pathname[:len(ps_pathname)]
|
||||
self.assertEqual(ps_pathname, adjusted_ps_pathname)
|
||||
|
||||
def test_process_cmdline(self):
|
||||
ps_cmdline = ps("ps --no-headers -o command -p %s" % self.pid)
|
||||
psutil_cmdline = " ".join(psutil.Process(self.pid).cmdline())
|
||||
if SUNOS:
|
||||
# ps on Solaris only shows the first part of the cmdline
|
||||
psutil_cmdline = psutil_cmdline.split(" ")[0]
|
||||
self.assertEqual(ps_cmdline, psutil_cmdline)
|
||||
|
||||
@retry_before_failing()
|
||||
def test_pids(self):
|
||||
# Note: this test might fail if the OS is starting/killing
|
||||
# other processes in the meantime
|
||||
if SUNOS:
|
||||
cmd = ["ps", "ax"]
|
||||
else:
|
||||
cmd = ["ps", "ax", "-o", "pid"]
|
||||
p = get_test_subprocess(cmd, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].strip()
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
pids_ps = []
|
||||
for line in output.split('\n')[1:]:
|
||||
if line:
|
||||
pid = int(line.split()[0].strip())
|
||||
pids_ps.append(pid)
|
||||
# remove ps subprocess pid which is supposed to be dead in meantime
|
||||
pids_ps.remove(p.pid)
|
||||
pids_psutil = psutil.pids()
|
||||
pids_ps.sort()
|
||||
pids_psutil.sort()
|
||||
|
||||
# on OSX ps doesn't show pid 0
|
||||
if OSX and 0 not in pids_ps:
|
||||
pids_ps.insert(0, 0)
|
||||
|
||||
if pids_ps != pids_psutil:
|
||||
difference = [x for x in pids_psutil if x not in pids_ps] + \
|
||||
[x for x in pids_ps if x not in pids_psutil]
|
||||
self.fail("difference: " + str(difference))
|
||||
|
||||
# for some reason ifconfig -a does not report all interfaces
|
||||
# returned by psutil
|
||||
@unittest.skipIf(SUNOS, "test not reliable on SUNOS")
|
||||
@unittest.skipIf(TRAVIS, "test not reliable on Travis")
|
||||
def test_nic_names(self):
|
||||
p = subprocess.Popen("ifconfig -a", shell=1, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].strip()
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
for nic in psutil.net_io_counters(pernic=True).keys():
|
||||
for line in output.split():
|
||||
if line.startswith(nic):
|
||||
break
|
||||
else:
|
||||
self.fail(
|
||||
"couldn't find %s nic in 'ifconfig -a' output\n%s" % (
|
||||
nic, output))
|
||||
|
||||
@retry_before_failing()
|
||||
def test_users(self):
|
||||
out = sh("who")
|
||||
lines = out.split('\n')
|
||||
users = [x.split()[0] for x in lines]
|
||||
self.assertEqual(len(users), len(psutil.users()))
|
||||
terminals = [x.split()[1] for x in lines]
|
||||
for u in psutil.users():
|
||||
self.assertTrue(u.name in users, u.name)
|
||||
self.assertTrue(u.terminal in terminals, u.terminal)
|
||||
|
||||
def test_fds_open(self):
|
||||
# Note: this fails from time to time; I'm keen on thinking
|
||||
# it doesn't mean something is broken
|
||||
def call(p, attr):
|
||||
args = ()
|
||||
attr = getattr(p, name, None)
|
||||
if attr is not None and callable(attr):
|
||||
if name == 'rlimit':
|
||||
args = (psutil.RLIMIT_NOFILE,)
|
||||
attr(*args)
|
||||
else:
|
||||
attr
|
||||
|
||||
p = psutil.Process(os.getpid())
|
||||
failures = []
|
||||
ignored_names = ['terminate', 'kill', 'suspend', 'resume', 'nice',
|
||||
'send_signal', 'wait', 'children', 'as_dict']
|
||||
if LINUX and get_kernel_version() < (2, 6, 36):
|
||||
ignored_names.append('rlimit')
|
||||
if LINUX and get_kernel_version() < (2, 6, 23):
|
||||
ignored_names.append('num_ctx_switches')
|
||||
for name in dir(psutil.Process):
|
||||
if (name.startswith('_') or name in ignored_names):
|
||||
continue
|
||||
else:
|
||||
try:
|
||||
num1 = p.num_fds()
|
||||
for x in range(2):
|
||||
call(p, name)
|
||||
num2 = p.num_fds()
|
||||
except psutil.AccessDenied:
|
||||
pass
|
||||
else:
|
||||
if abs(num2 - num1) > 1:
|
||||
fail = "failure while processing Process.%s method " \
|
||||
"(before=%s, after=%s)" % (name, num1, num2)
|
||||
failures.append(fail)
|
||||
if failures:
|
||||
self.fail('\n' + '\n'.join(failures))
|
||||
|
||||
|
||||
def main():
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(PosixSpecificTestCase))
|
||||
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
return result.wasSuccessful()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not main():
|
||||
sys.exit(1)
|
||||
48
python/psutil/test/_sunos.py
Normal file
48
python/psutil/test/_sunos.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Sun OS specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from test_psutil import SUNOS, sh, unittest
|
||||
import psutil
|
||||
|
||||
|
||||
@unittest.skipUnless(SUNOS, "not a SunOS system")
|
||||
class SunOSSpecificTestCase(unittest.TestCase):
|
||||
|
||||
def test_swap_memory(self):
|
||||
out = sh('env PATH=/usr/sbin:/sbin:%s swap -l -k' % os.environ['PATH'])
|
||||
lines = out.strip().split('\n')[1:]
|
||||
if not lines:
|
||||
raise ValueError('no swap device(s) configured')
|
||||
total = free = 0
|
||||
for line in lines:
|
||||
line = line.split()
|
||||
t, f = line[-2:]
|
||||
t = t.replace('K', '')
|
||||
f = f.replace('K', '')
|
||||
total += int(int(t) * 1024)
|
||||
free += int(int(f) * 1024)
|
||||
used = total - free
|
||||
|
||||
psutil_swap = psutil.swap_memory()
|
||||
self.assertEqual(psutil_swap.total, total)
|
||||
self.assertEqual(psutil_swap.used, used)
|
||||
self.assertEqual(psutil_swap.free, free)
|
||||
|
||||
|
||||
def main():
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(SunOSSpecificTestCase))
|
||||
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
return result.wasSuccessful()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not main():
|
||||
sys.exit(1)
|
||||
464
python/psutil/test/_windows.py
Normal file
464
python/psutil/test/_windows.py
Normal file
|
|
@ -0,0 +1,464 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Windows specific tests. These are implicitly run by test_psutil.py."""
|
||||
|
||||
import errno
|
||||
import os
|
||||
import platform
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from test_psutil import APPVEYOR, WINDOWS
|
||||
from test_psutil import get_test_subprocess, reap_children, unittest
|
||||
|
||||
import mock
|
||||
try:
|
||||
import wmi
|
||||
except ImportError:
|
||||
wmi = None
|
||||
try:
|
||||
import win32api
|
||||
import win32con
|
||||
except ImportError:
|
||||
win32api = win32con = None
|
||||
|
||||
from psutil._compat import PY3, callable, long
|
||||
import psutil
|
||||
|
||||
|
||||
cext = psutil._psplatform.cext
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
from psutil._pswindows import ACCESS_DENIED_SET
|
||||
if err.errno in ACCESS_DENIED_SET:
|
||||
raise psutil.AccessDenied(None, None)
|
||||
if err.errno == errno.ESRCH:
|
||||
raise psutil.NoSuchProcess(None, None)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
@unittest.skipUnless(WINDOWS, "not a Windows system")
|
||||
class WindowsSpecificTestCase(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_issue_24(self):
|
||||
p = psutil.Process(0)
|
||||
self.assertRaises(psutil.AccessDenied, p.kill)
|
||||
|
||||
def test_special_pid(self):
|
||||
p = psutil.Process(4)
|
||||
self.assertEqual(p.name(), 'System')
|
||||
# use __str__ to access all common Process properties to check
|
||||
# that nothing strange happens
|
||||
str(p)
|
||||
p.username()
|
||||
self.assertTrue(p.create_time() >= 0.0)
|
||||
try:
|
||||
rss, vms = p.memory_info()
|
||||
except psutil.AccessDenied:
|
||||
# expected on Windows Vista and Windows 7
|
||||
if not platform.uname()[1] in ('vista', 'win-7', 'win7'):
|
||||
raise
|
||||
else:
|
||||
self.assertTrue(rss > 0)
|
||||
|
||||
def test_send_signal(self):
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertRaises(ValueError, p.send_signal, signal.SIGINT)
|
||||
|
||||
def test_nic_names(self):
|
||||
p = subprocess.Popen(['ipconfig', '/all'], stdout=subprocess.PIPE)
|
||||
out = p.communicate()[0]
|
||||
if PY3:
|
||||
out = str(out, sys.stdout.encoding)
|
||||
nics = psutil.net_io_counters(pernic=True).keys()
|
||||
for nic in nics:
|
||||
if "pseudo-interface" in nic.replace(' ', '-').lower():
|
||||
continue
|
||||
if nic not in out:
|
||||
self.fail(
|
||||
"%r nic wasn't found in 'ipconfig /all' output" % nic)
|
||||
|
||||
def test_exe(self):
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
self.assertEqual(os.path.basename(p.exe()), p.name())
|
||||
except psutil.Error:
|
||||
pass
|
||||
|
||||
# --- Process class tests
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_process_name(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertEqual(p.name(), w.Caption)
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_process_exe(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
# Note: wmi reports the exe as a lower case string.
|
||||
# Being Windows paths case-insensitive we ignore that.
|
||||
self.assertEqual(p.exe().lower(), w.ExecutablePath.lower())
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_process_cmdline(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertEqual(' '.join(p.cmdline()),
|
||||
w.CommandLine.replace('"', ''))
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_process_username(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
domain, _, username = w.GetOwner()
|
||||
username = "%s\\%s" % (domain, username)
|
||||
self.assertEqual(p.username(), username)
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_process_rss_memory(self):
|
||||
time.sleep(0.1)
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
rss = p.memory_info().rss
|
||||
self.assertEqual(rss, int(w.WorkingSetSize))
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_process_vms_memory(self):
|
||||
time.sleep(0.1)
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
vms = p.memory_info().vms
|
||||
# http://msdn.microsoft.com/en-us/library/aa394372(VS.85).aspx
|
||||
# ...claims that PageFileUsage is represented in Kilo
|
||||
# bytes but funnily enough on certain platforms bytes are
|
||||
# returned instead.
|
||||
wmi_usage = int(w.PageFileUsage)
|
||||
if (vms != wmi_usage) and (vms != wmi_usage * 1024):
|
||||
self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms))
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_process_create_time(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
wmic_create = str(w.CreationDate.split('.')[0])
|
||||
psutil_create = time.strftime("%Y%m%d%H%M%S",
|
||||
time.localtime(p.create_time()))
|
||||
self.assertEqual(wmic_create, psutil_create)
|
||||
|
||||
# --- psutil namespace functions and constants tests
|
||||
|
||||
@unittest.skipUnless('NUMBER_OF_PROCESSORS' in os.environ,
|
||||
'NUMBER_OF_PROCESSORS env var is not available')
|
||||
def test_cpu_count(self):
|
||||
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
|
||||
self.assertEqual(num_cpus, psutil.cpu_count())
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_total_phymem(self):
|
||||
w = wmi.WMI().Win32_ComputerSystem()[0]
|
||||
self.assertEqual(int(w.TotalPhysicalMemory),
|
||||
psutil.virtual_memory().total)
|
||||
|
||||
# @unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
# def test__UPTIME(self):
|
||||
# # _UPTIME constant is not public but it is used internally
|
||||
# # as value to return for pid 0 creation time.
|
||||
# # WMI behaves the same.
|
||||
# w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
# p = psutil.Process(0)
|
||||
# wmic_create = str(w.CreationDate.split('.')[0])
|
||||
# psutil_create = time.strftime("%Y%m%d%H%M%S",
|
||||
# time.localtime(p.create_time()))
|
||||
#
|
||||
|
||||
# Note: this test is not very reliable
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
@unittest.skipIf(APPVEYOR, "test not relieable on appveyor")
|
||||
def test_pids(self):
|
||||
# Note: this test might fail if the OS is starting/killing
|
||||
# other processes in the meantime
|
||||
w = wmi.WMI().Win32_Process()
|
||||
wmi_pids = set([x.ProcessId for x in w])
|
||||
psutil_pids = set(psutil.pids())
|
||||
self.assertEqual(wmi_pids, psutil_pids)
|
||||
|
||||
@unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
def test_disks(self):
|
||||
ps_parts = psutil.disk_partitions(all=True)
|
||||
wmi_parts = wmi.WMI().Win32_LogicalDisk()
|
||||
for ps_part in ps_parts:
|
||||
for wmi_part in wmi_parts:
|
||||
if ps_part.device.replace('\\', '') == wmi_part.DeviceID:
|
||||
if not ps_part.mountpoint:
|
||||
# this is usually a CD-ROM with no disk inserted
|
||||
break
|
||||
try:
|
||||
usage = psutil.disk_usage(ps_part.mountpoint)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
# usually this is the floppy
|
||||
break
|
||||
else:
|
||||
raise
|
||||
self.assertEqual(usage.total, int(wmi_part.Size))
|
||||
wmi_free = int(wmi_part.FreeSpace)
|
||||
self.assertEqual(usage.free, wmi_free)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - wmi_free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, wmi=%s" % (
|
||||
usage.free, wmi_free))
|
||||
break
|
||||
else:
|
||||
self.fail("can't find partition %s" % repr(ps_part))
|
||||
|
||||
@unittest.skipIf(win32api is None, "pywin32 module is not installed")
|
||||
def test_num_handles(self):
|
||||
p = psutil.Process(os.getpid())
|
||||
before = p.num_handles()
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
win32con.FALSE, os.getpid())
|
||||
after = p.num_handles()
|
||||
self.assertEqual(after, before + 1)
|
||||
win32api.CloseHandle(handle)
|
||||
self.assertEqual(p.num_handles(), before)
|
||||
|
||||
@unittest.skipIf(win32api is None, "pywin32 module is not installed")
|
||||
def test_num_handles_2(self):
|
||||
# Note: this fails from time to time; I'm keen on thinking
|
||||
# it doesn't mean something is broken
|
||||
def call(p, attr):
|
||||
attr = getattr(p, name, None)
|
||||
if attr is not None and callable(attr):
|
||||
attr()
|
||||
else:
|
||||
attr
|
||||
|
||||
p = psutil.Process(self.pid)
|
||||
failures = []
|
||||
for name in dir(psutil.Process):
|
||||
if name.startswith('_') \
|
||||
or name in ('terminate', 'kill', 'suspend', 'resume',
|
||||
'nice', 'send_signal', 'wait', 'children',
|
||||
'as_dict'):
|
||||
continue
|
||||
else:
|
||||
try:
|
||||
call(p, name)
|
||||
num1 = p.num_handles()
|
||||
call(p, name)
|
||||
num2 = p.num_handles()
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
else:
|
||||
if num2 > num1:
|
||||
fail = \
|
||||
"failure while processing Process.%s method " \
|
||||
"(before=%s, after=%s)" % (name, num1, num2)
|
||||
failures.append(fail)
|
||||
if failures:
|
||||
self.fail('\n' + '\n'.join(failures))
|
||||
|
||||
def test_name_always_available(self):
|
||||
# On Windows name() is never supposed to raise AccessDenied,
|
||||
# see https://github.com/giampaolo/psutil/issues/627
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
p.name()
|
||||
except psutil.NoSuchProcess():
|
||||
pass
|
||||
|
||||
|
||||
@unittest.skipUnless(WINDOWS, "not a Windows system")
|
||||
class TestDualProcessImplementation(unittest.TestCase):
|
||||
"""
|
||||
Certain APIs on Windows have 2 internal implementations, one
|
||||
based on documented Windows APIs, another one based
|
||||
NtQuerySystemInformation() which gets called as fallback in
|
||||
case the first fails because of limited permission error.
|
||||
Here we test that the two methods return the exact same value,
|
||||
see:
|
||||
https://github.com/giampaolo/psutil/issues/304
|
||||
"""
|
||||
|
||||
fun_names = [
|
||||
# function name, tolerance
|
||||
('proc_cpu_times', 0.2),
|
||||
('proc_create_time', 0.5),
|
||||
('proc_num_handles', 1), # 1 because impl #1 opens a handle
|
||||
('proc_memory_info', 1024), # KB
|
||||
('proc_io_counters', 0),
|
||||
]
|
||||
|
||||
def test_compare_values(self):
|
||||
def assert_ge_0(obj):
|
||||
if isinstance(obj, tuple):
|
||||
for value in obj:
|
||||
self.assertGreaterEqual(value, 0, msg=obj)
|
||||
elif isinstance(obj, (int, long, float)):
|
||||
self.assertGreaterEqual(obj, 0)
|
||||
else:
|
||||
assert 0 # case not handled which needs to be fixed
|
||||
|
||||
def compare_with_tolerance(ret1, ret2, tolerance):
|
||||
if ret1 == ret2:
|
||||
return
|
||||
else:
|
||||
if isinstance(ret2, (int, long, float)):
|
||||
diff = abs(ret1 - ret2)
|
||||
self.assertLessEqual(diff, tolerance)
|
||||
elif isinstance(ret2, tuple):
|
||||
for a, b in zip(ret1, ret2):
|
||||
diff = abs(a - b)
|
||||
self.assertLessEqual(diff, tolerance)
|
||||
|
||||
from psutil._pswindows import ntpinfo
|
||||
failures = []
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
nt = ntpinfo(*cext.proc_info(p.pid))
|
||||
except psutil.NoSuchProcess:
|
||||
continue
|
||||
assert_ge_0(nt)
|
||||
|
||||
for name, tolerance in self.fun_names:
|
||||
if name == 'proc_memory_info' and p.pid == os.getpid():
|
||||
continue
|
||||
if name == 'proc_create_time' and p.pid in (0, 4):
|
||||
continue
|
||||
meth = wrap_exceptions(getattr(cext, name))
|
||||
try:
|
||||
ret = meth(p.pid)
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
continue
|
||||
# compare values
|
||||
try:
|
||||
if name == 'proc_cpu_times':
|
||||
compare_with_tolerance(ret[0], nt.user_time, tolerance)
|
||||
compare_with_tolerance(ret[1],
|
||||
nt.kernel_time, tolerance)
|
||||
elif name == 'proc_create_time':
|
||||
compare_with_tolerance(ret, nt.create_time, tolerance)
|
||||
elif name == 'proc_num_handles':
|
||||
compare_with_tolerance(ret, nt.num_handles, tolerance)
|
||||
elif name == 'proc_io_counters':
|
||||
compare_with_tolerance(ret[0], nt.io_rcount, tolerance)
|
||||
compare_with_tolerance(ret[1], nt.io_wcount, tolerance)
|
||||
compare_with_tolerance(ret[2], nt.io_rbytes, tolerance)
|
||||
compare_with_tolerance(ret[3], nt.io_wbytes, tolerance)
|
||||
elif name == 'proc_memory_info':
|
||||
try:
|
||||
rawtupl = cext.proc_memory_info_2(p.pid)
|
||||
except psutil.NoSuchProcess:
|
||||
continue
|
||||
compare_with_tolerance(ret, rawtupl, tolerance)
|
||||
except AssertionError:
|
||||
trace = traceback.format_exc()
|
||||
msg = '%s\npid=%s, method=%r, ret_1=%r, ret_2=%r' % (
|
||||
trace, p.pid, name, ret, nt)
|
||||
failures.append(msg)
|
||||
break
|
||||
|
||||
if failures:
|
||||
self.fail('\n\n'.join(failures))
|
||||
|
||||
# ---
|
||||
# same tests as above but mimicks the AccessDenied failure of
|
||||
# the first (fast) method failing with AD.
|
||||
# TODO: currently does not take tolerance into account.
|
||||
|
||||
def test_name(self):
|
||||
name = psutil.Process().name()
|
||||
with mock.patch("psutil._psplatform.cext.proc_exe",
|
||||
side_effect=psutil.AccessDenied(os.getpid())) as fun:
|
||||
psutil.Process().name() == name
|
||||
assert fun.called
|
||||
|
||||
def test_memory_info(self):
|
||||
mem = psutil.Process().memory_info()
|
||||
with mock.patch("psutil._psplatform.cext.proc_memory_info",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
psutil.Process().memory_info() == mem
|
||||
assert fun.called
|
||||
|
||||
def test_create_time(self):
|
||||
ctime = psutil.Process().create_time()
|
||||
with mock.patch("psutil._psplatform.cext.proc_create_time",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
psutil.Process().create_time() == ctime
|
||||
assert fun.called
|
||||
|
||||
def test_cpu_times(self):
|
||||
cpu_times = psutil.Process().cpu_times()
|
||||
with mock.patch("psutil._psplatform.cext.proc_cpu_times",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
psutil.Process().cpu_times() == cpu_times
|
||||
assert fun.called
|
||||
|
||||
def test_io_counters(self):
|
||||
io_counters = psutil.Process().io_counters()
|
||||
with mock.patch("psutil._psplatform.cext.proc_io_counters",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
psutil.Process().io_counters() == io_counters
|
||||
assert fun.called
|
||||
|
||||
def test_num_handles(self):
|
||||
io_counters = psutil.Process().io_counters()
|
||||
with mock.patch("psutil._psplatform.cext.proc_io_counters",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
psutil.Process().io_counters() == io_counters
|
||||
assert fun.called
|
||||
|
||||
# --- other tests
|
||||
|
||||
def test_compare_name_exe(self):
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
a = os.path.basename(p.exe())
|
||||
b = p.name()
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
else:
|
||||
self.assertEqual(a, b)
|
||||
|
||||
def test_zombies(self):
|
||||
# test that NPS is raised by the 2nd implementation in case a
|
||||
# process no longer exists
|
||||
ZOMBIE_PID = max(psutil.pids()) + 5000
|
||||
for name, _ in self.fun_names:
|
||||
meth = wrap_exceptions(getattr(cext, name))
|
||||
self.assertRaises(psutil.NoSuchProcess, meth, ZOMBIE_PID)
|
||||
|
||||
|
||||
def main():
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(WindowsSpecificTestCase))
|
||||
test_suite.addTest(unittest.makeSuite(TestDualProcessImplementation))
|
||||
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
return result.wasSuccessful()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not main():
|
||||
sys.exit(1)
|
||||
445
python/psutil/test/test_memory_leaks.py
Normal file
445
python/psutil/test/test_memory_leaks.py
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
A test script which attempts to detect memory leaks by calling C
|
||||
functions many times and compare process memory usage before and
|
||||
after the calls. It might produce false positives.
|
||||
"""
|
||||
|
||||
import functools
|
||||
import gc
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
import psutil
|
||||
import psutil._common
|
||||
|
||||
from psutil._compat import xrange, callable
|
||||
from test_psutil import (WINDOWS, POSIX, OSX, LINUX, SUNOS, BSD, TESTFN,
|
||||
RLIMIT_SUPPORT, TRAVIS)
|
||||
from test_psutil import (reap_children, supports_ipv6, safe_remove,
|
||||
get_test_subprocess)
|
||||
|
||||
if sys.version_info < (2, 7):
|
||||
import unittest2 as unittest # https://pypi.python.org/pypi/unittest2
|
||||
else:
|
||||
import unittest
|
||||
|
||||
|
||||
LOOPS = 1000
|
||||
TOLERANCE = 4096
|
||||
SKIP_PYTHON_IMPL = True
|
||||
|
||||
|
||||
def skip_if_linux():
|
||||
return unittest.skipIf(LINUX and SKIP_PYTHON_IMPL,
|
||||
"not worth being tested on LINUX (pure python)")
|
||||
|
||||
|
||||
class Base(unittest.TestCase):
|
||||
proc = psutil.Process()
|
||||
|
||||
def execute(self, function, *args, **kwargs):
|
||||
def call_many_times():
|
||||
for x in xrange(LOOPS - 1):
|
||||
self.call(function, *args, **kwargs)
|
||||
del x
|
||||
gc.collect()
|
||||
return self.get_mem()
|
||||
|
||||
self.call(function, *args, **kwargs)
|
||||
self.assertEqual(gc.garbage, [])
|
||||
self.assertEqual(threading.active_count(), 1)
|
||||
|
||||
# RSS comparison
|
||||
# step 1
|
||||
rss1 = call_many_times()
|
||||
# step 2
|
||||
rss2 = call_many_times()
|
||||
|
||||
difference = rss2 - rss1
|
||||
if difference > TOLERANCE:
|
||||
# This doesn't necessarily mean we have a leak yet.
|
||||
# At this point we assume that after having called the
|
||||
# function so many times the memory usage is stabilized
|
||||
# and if there are no leaks it should not increase any
|
||||
# more.
|
||||
# Let's keep calling fun for 3 more seconds and fail if
|
||||
# we notice any difference.
|
||||
stop_at = time.time() + 3
|
||||
while True:
|
||||
self.call(function, *args, **kwargs)
|
||||
if time.time() >= stop_at:
|
||||
break
|
||||
del stop_at
|
||||
gc.collect()
|
||||
rss3 = self.get_mem()
|
||||
difference = rss3 - rss2
|
||||
if rss3 > rss2:
|
||||
self.fail("rss2=%s, rss3=%s, difference=%s"
|
||||
% (rss2, rss3, difference))
|
||||
|
||||
def execute_w_exc(self, exc, function, *args, **kwargs):
|
||||
kwargs['_exc'] = exc
|
||||
self.execute(function, *args, **kwargs)
|
||||
|
||||
def get_mem(self):
|
||||
return psutil.Process().memory_info()[0]
|
||||
|
||||
def call(self, function, *args, **kwargs):
|
||||
raise NotImplementedError("must be implemented in subclass")
|
||||
|
||||
|
||||
class TestProcessObjectLeaks(Base):
|
||||
"""Test leaks of Process class methods and properties"""
|
||||
|
||||
def setUp(self):
|
||||
gc.collect()
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
def call(self, function, *args, **kwargs):
|
||||
if callable(function):
|
||||
if '_exc' in kwargs:
|
||||
exc = kwargs.pop('_exc')
|
||||
self.assertRaises(exc, function, *args, **kwargs)
|
||||
else:
|
||||
try:
|
||||
function(*args, **kwargs)
|
||||
except psutil.Error:
|
||||
pass
|
||||
else:
|
||||
meth = getattr(self.proc, function)
|
||||
if '_exc' in kwargs:
|
||||
exc = kwargs.pop('_exc')
|
||||
self.assertRaises(exc, meth, *args, **kwargs)
|
||||
else:
|
||||
try:
|
||||
meth(*args, **kwargs)
|
||||
except psutil.Error:
|
||||
pass
|
||||
|
||||
@skip_if_linux()
|
||||
def test_name(self):
|
||||
self.execute('name')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cmdline(self):
|
||||
self.execute('cmdline')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_exe(self):
|
||||
self.execute('exe')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_ppid(self):
|
||||
self.execute('ppid')
|
||||
|
||||
@unittest.skipUnless(POSIX, "POSIX only")
|
||||
@skip_if_linux()
|
||||
def test_uids(self):
|
||||
self.execute('uids')
|
||||
|
||||
@unittest.skipUnless(POSIX, "POSIX only")
|
||||
@skip_if_linux()
|
||||
def test_gids(self):
|
||||
self.execute('gids')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_status(self):
|
||||
self.execute('status')
|
||||
|
||||
def test_nice_get(self):
|
||||
self.execute('nice')
|
||||
|
||||
def test_nice_set(self):
|
||||
niceness = psutil.Process().nice()
|
||||
self.execute('nice', niceness)
|
||||
|
||||
@unittest.skipUnless(hasattr(psutil.Process, 'ionice'),
|
||||
"Linux and Windows Vista only")
|
||||
def test_ionice_get(self):
|
||||
self.execute('ionice')
|
||||
|
||||
@unittest.skipUnless(hasattr(psutil.Process, 'ionice'),
|
||||
"Linux and Windows Vista only")
|
||||
def test_ionice_set(self):
|
||||
if WINDOWS:
|
||||
value = psutil.Process().ionice()
|
||||
self.execute('ionice', value)
|
||||
else:
|
||||
from psutil._pslinux import cext
|
||||
self.execute('ionice', psutil.IOPRIO_CLASS_NONE)
|
||||
fun = functools.partial(cext.proc_ioprio_set, os.getpid(), -1, 0)
|
||||
self.execute_w_exc(OSError, fun)
|
||||
|
||||
@unittest.skipIf(OSX or SUNOS, "feature not supported on this platform")
|
||||
@skip_if_linux()
|
||||
def test_io_counters(self):
|
||||
self.execute('io_counters')
|
||||
|
||||
@unittest.skipUnless(WINDOWS, "not worth being tested on posix")
|
||||
def test_username(self):
|
||||
self.execute('username')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_create_time(self):
|
||||
self.execute('create_time')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_num_threads(self):
|
||||
self.execute('num_threads')
|
||||
|
||||
@unittest.skipUnless(WINDOWS, "Windows only")
|
||||
def test_num_handles(self):
|
||||
self.execute('num_handles')
|
||||
|
||||
@unittest.skipUnless(POSIX, "POSIX only")
|
||||
@skip_if_linux()
|
||||
def test_num_fds(self):
|
||||
self.execute('num_fds')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_threads(self):
|
||||
self.execute('threads')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_times(self):
|
||||
self.execute('cpu_times')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_memory_info(self):
|
||||
self.execute('memory_info')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_memory_info_ex(self):
|
||||
self.execute('memory_info_ex')
|
||||
|
||||
@unittest.skipUnless(POSIX, "POSIX only")
|
||||
@skip_if_linux()
|
||||
def test_terminal(self):
|
||||
self.execute('terminal')
|
||||
|
||||
@unittest.skipIf(POSIX and SKIP_PYTHON_IMPL,
|
||||
"not worth being tested on POSIX (pure python)")
|
||||
def test_resume(self):
|
||||
self.execute('resume')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cwd(self):
|
||||
self.execute('cwd')
|
||||
|
||||
@unittest.skipUnless(WINDOWS or LINUX or BSD,
|
||||
"Windows or Linux or BSD only")
|
||||
def test_cpu_affinity_get(self):
|
||||
self.execute('cpu_affinity')
|
||||
|
||||
@unittest.skipUnless(WINDOWS or LINUX or BSD,
|
||||
"Windows or Linux or BSD only")
|
||||
def test_cpu_affinity_set(self):
|
||||
affinity = psutil.Process().cpu_affinity()
|
||||
self.execute('cpu_affinity', affinity)
|
||||
if not TRAVIS:
|
||||
self.execute_w_exc(ValueError, 'cpu_affinity', [-1])
|
||||
|
||||
@skip_if_linux()
|
||||
def test_open_files(self):
|
||||
safe_remove(TESTFN) # needed after UNIX socket test has run
|
||||
with open(TESTFN, 'w'):
|
||||
self.execute('open_files')
|
||||
|
||||
# OSX implementation is unbelievably slow
|
||||
@unittest.skipIf(OSX, "OSX implementation is too slow")
|
||||
@skip_if_linux()
|
||||
def test_memory_maps(self):
|
||||
self.execute('memory_maps')
|
||||
|
||||
@unittest.skipUnless(LINUX, "Linux only")
|
||||
@unittest.skipUnless(LINUX and RLIMIT_SUPPORT,
|
||||
"only available on Linux >= 2.6.36")
|
||||
def test_rlimit_get(self):
|
||||
self.execute('rlimit', psutil.RLIMIT_NOFILE)
|
||||
|
||||
@unittest.skipUnless(LINUX, "Linux only")
|
||||
@unittest.skipUnless(LINUX and RLIMIT_SUPPORT,
|
||||
"only available on Linux >= 2.6.36")
|
||||
def test_rlimit_set(self):
|
||||
limit = psutil.Process().rlimit(psutil.RLIMIT_NOFILE)
|
||||
self.execute('rlimit', psutil.RLIMIT_NOFILE, limit)
|
||||
self.execute_w_exc(OSError, 'rlimit', -1)
|
||||
|
||||
@skip_if_linux()
|
||||
# Windows implementation is based on a single system-wide function
|
||||
@unittest.skipIf(WINDOWS, "tested later")
|
||||
def test_connections(self):
|
||||
def create_socket(family, type):
|
||||
sock = socket.socket(family, type)
|
||||
sock.bind(('', 0))
|
||||
if type == socket.SOCK_STREAM:
|
||||
sock.listen(1)
|
||||
return sock
|
||||
|
||||
socks = []
|
||||
socks.append(create_socket(socket.AF_INET, socket.SOCK_STREAM))
|
||||
socks.append(create_socket(socket.AF_INET, socket.SOCK_DGRAM))
|
||||
if supports_ipv6():
|
||||
socks.append(create_socket(socket.AF_INET6, socket.SOCK_STREAM))
|
||||
socks.append(create_socket(socket.AF_INET6, socket.SOCK_DGRAM))
|
||||
if hasattr(socket, 'AF_UNIX'):
|
||||
safe_remove(TESTFN)
|
||||
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
s.bind(TESTFN)
|
||||
s.listen(1)
|
||||
socks.append(s)
|
||||
kind = 'all'
|
||||
# TODO: UNIX sockets are temporarily implemented by parsing
|
||||
# 'pfiles' cmd output; we don't want that part of the code to
|
||||
# be executed.
|
||||
if SUNOS:
|
||||
kind = 'inet'
|
||||
try:
|
||||
self.execute('connections', kind=kind)
|
||||
finally:
|
||||
for s in socks:
|
||||
s.close()
|
||||
|
||||
|
||||
p = get_test_subprocess()
|
||||
DEAD_PROC = psutil.Process(p.pid)
|
||||
DEAD_PROC.kill()
|
||||
DEAD_PROC.wait()
|
||||
del p
|
||||
|
||||
|
||||
class TestProcessObjectLeaksZombie(TestProcessObjectLeaks):
|
||||
"""Same as above but looks for leaks occurring when dealing with
|
||||
zombie processes raising NoSuchProcess exception.
|
||||
"""
|
||||
proc = DEAD_PROC
|
||||
|
||||
def call(self, *args, **kwargs):
|
||||
try:
|
||||
TestProcessObjectLeaks.call(self, *args, **kwargs)
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
if not POSIX:
|
||||
def test_kill(self):
|
||||
self.execute('kill')
|
||||
|
||||
def test_terminate(self):
|
||||
self.execute('terminate')
|
||||
|
||||
def test_suspend(self):
|
||||
self.execute('suspend')
|
||||
|
||||
def test_resume(self):
|
||||
self.execute('resume')
|
||||
|
||||
def test_wait(self):
|
||||
self.execute('wait')
|
||||
|
||||
|
||||
class TestModuleFunctionsLeaks(Base):
|
||||
"""Test leaks of psutil module functions."""
|
||||
|
||||
def setUp(self):
|
||||
gc.collect()
|
||||
|
||||
def call(self, function, *args, **kwargs):
|
||||
fun = getattr(psutil, function)
|
||||
fun(*args, **kwargs)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_count_logical(self):
|
||||
psutil.cpu_count = psutil._psplatform.cpu_count_logical
|
||||
self.execute('cpu_count')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_count_physical(self):
|
||||
psutil.cpu_count = psutil._psplatform.cpu_count_physical
|
||||
self.execute('cpu_count')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_boot_time(self):
|
||||
self.execute('boot_time')
|
||||
|
||||
@unittest.skipIf(POSIX and SKIP_PYTHON_IMPL,
|
||||
"not worth being tested on POSIX (pure python)")
|
||||
def test_pid_exists(self):
|
||||
self.execute('pid_exists', os.getpid())
|
||||
|
||||
def test_virtual_memory(self):
|
||||
self.execute('virtual_memory')
|
||||
|
||||
# TODO: remove this skip when this gets fixed
|
||||
@unittest.skipIf(SUNOS,
|
||||
"not worth being tested on SUNOS (uses a subprocess)")
|
||||
def test_swap_memory(self):
|
||||
self.execute('swap_memory')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_times(self):
|
||||
self.execute('cpu_times')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_per_cpu_times(self):
|
||||
self.execute('cpu_times', percpu=True)
|
||||
|
||||
@unittest.skipIf(POSIX and SKIP_PYTHON_IMPL,
|
||||
"not worth being tested on POSIX (pure python)")
|
||||
def test_disk_usage(self):
|
||||
self.execute('disk_usage', '.')
|
||||
|
||||
def test_disk_partitions(self):
|
||||
self.execute('disk_partitions')
|
||||
|
||||
@skip_if_linux()
|
||||
def test_net_io_counters(self):
|
||||
self.execute('net_io_counters')
|
||||
|
||||
@unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'),
|
||||
'/proc/diskstats not available on this Linux version')
|
||||
@skip_if_linux()
|
||||
def test_disk_io_counters(self):
|
||||
self.execute('disk_io_counters')
|
||||
|
||||
# XXX - on Windows this produces a false positive
|
||||
@unittest.skipIf(WINDOWS, "XXX produces a false positive on Windows")
|
||||
def test_users(self):
|
||||
self.execute('users')
|
||||
|
||||
@unittest.skipIf(LINUX,
|
||||
"not worth being tested on Linux (pure python)")
|
||||
def test_net_connections(self):
|
||||
self.execute('net_connections')
|
||||
|
||||
def test_net_if_addrs(self):
|
||||
self.execute('net_if_addrs')
|
||||
|
||||
@unittest.skipIf(TRAVIS, "EPERM on travis")
|
||||
def test_net_if_stats(self):
|
||||
self.execute('net_if_stats')
|
||||
|
||||
|
||||
def main():
|
||||
test_suite = unittest.TestSuite()
|
||||
tests = [TestProcessObjectLeaksZombie,
|
||||
TestProcessObjectLeaks,
|
||||
TestModuleFunctionsLeaks]
|
||||
for test in tests:
|
||||
test_suite.addTest(unittest.makeSuite(test))
|
||||
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||
return result.wasSuccessful()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not main():
|
||||
sys.exit(1)
|
||||
3013
python/psutil/test/test_psutil.py
Normal file
3013
python/psutil/test/test_psutil.py
Normal file
File diff suppressed because it is too large
Load diff
32
python/psutil/tox.ini
Normal file
32
python/psutil/tox.ini
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Tox (http://tox.testrun.org/) is a tool for running tests
|
||||
# in multiple virtualenvs. This configuration file will run the
|
||||
# test suite on all supported python versions.
|
||||
# To use it run "pip install tox" and then run "tox" from this
|
||||
# directory.
|
||||
|
||||
[tox]
|
||||
envlist = py26, py27, py32, py33, py34
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
flake8
|
||||
pytest
|
||||
py26: ipaddress
|
||||
py26: mock==1.0.1
|
||||
py26: unittest2
|
||||
py27: ipaddress
|
||||
py27: mock
|
||||
py32: ipaddress
|
||||
py32: mock
|
||||
py33: ipaddress
|
||||
|
||||
setenv =
|
||||
PYTHONPATH = {toxinidir}/test
|
||||
|
||||
commands =
|
||||
py.test {posargs}
|
||||
git ls-files | grep \\.py$ | xargs flake8
|
||||
|
||||
# suppress "WARNING: 'git' command found but not installed in testenv
|
||||
whitelist_externals = git
|
||||
usedevelop = True
|
||||
Loading…
Add table
Add a link
Reference in a new issue