import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

310
python/psutil/CREDITS Normal file
View 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

File diff suppressed because it is too large Load diff

116
python/psutil/INSTALL.rst Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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.

View 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">&gt;&gt;&gt;</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

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

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
View 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>&laquo;</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();
});

View 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>

View file

@ -0,0 +1,4 @@
{% extends "defindex.html" %}
{% block tables %}
{% endblock %}

View 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
View 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">
&copy; 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 %}

View 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;
}

View 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
View 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

File diff suppressed because it is too large Load diff

242
python/psutil/docs/make.bat Normal file
View 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
View 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

View 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())

View 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()

View 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()

View 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()

View 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())

View 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()

View 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()

View 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()

View 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()

View 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()

View 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())

View 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()

View 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()

View 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()

View 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
View 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

File diff suppressed because it is too large Load diff

View 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'])

View 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

View 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

File diff suppressed because it is too large Load diff

View 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)

View 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

View 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)

File diff suppressed because it is too large Load diff

View 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

View 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;
}

View 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);

View 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(&ethcmd, 0, sizeof ethcmd);
ethcmd.cmd = ETHTOOL_GSET;
ifr.ifr_data = (caddr_t)&ethcmd;
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
}

View 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);

File diff suppressed because it is too large Load diff

View 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);

View 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
}

View 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

File diff suppressed because it is too large Load diff

View 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);

File diff suppressed because it is too large Load diff

View 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);

View 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)

View 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;
}

View 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);

View 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;
}
}

View 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);

View 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);

View 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;
}

View 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
);

View 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__

View 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;
}

View 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__

View 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;
}

View 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

View 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;
}

View 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
View file

@ -0,0 +1,5 @@
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0

206
python/psutil/setup.py Normal file
View 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()

View 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
View 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)

View 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
View 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)

View 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)

View 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)

View 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)

View 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)

File diff suppressed because it is too large Load diff

32
python/psutil/tox.ini Normal file
View 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