Skip to content

Commit

Permalink
Merge 77586cb into c67ab01
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Feb 14, 2020
2 parents c67ab01 + 77586cb commit 0396b4a
Show file tree
Hide file tree
Showing 23 changed files with 394 additions and 27 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -17,7 +17,7 @@ DEPS = \
pyperf \
requests \
setuptools \
sphinx \
sphinx==2.3.1 \
twine \
unittest2 \
virtualenv \
Expand Down
17 changes: 17 additions & 0 deletions docs/index.rst
Expand Up @@ -493,6 +493,23 @@ Disks
.. versionchanged::
4.0.0 NetBSD no longer has *read_time* and *write_time* fields.

.. function:: disk_swaps()

Enumerate swap partitions and swap files as a list of namedtuples including:

- **path**: the path of the swap partition/file on disk
- **total**: total swap partition/file size
- **used**: used swap partition/file size
- **fstype** (Linux): either "partition" or "swapfile"
- **priority** (Linux): makes sense when multiple swap files are in use.
The lower the priority, the more likely the swap file is o be used.
- **peak** (Windows): the highest peak usage over time.

Availability: Linux, Windows, FreeBSD

.. versionadded:: 5.7.1


Network
-------

Expand Down
20 changes: 20 additions & 0 deletions psutil/__init__.py
Expand Up @@ -220,6 +220,7 @@
"net_io_counters", "net_connections", "net_if_addrs", # network
"net_if_stats",
"disk_io_counters", "disk_partitions", "disk_usage", # disk
# "disk_swaps"
# "sensors_temperatures", "sensors_battery", "sensors_fans" # sensors
"users", "boot_time", # others
]
Expand Down Expand Up @@ -2081,6 +2082,25 @@ def disk_io_counters(perdisk=False, nowrap=True):
disk_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"


# Linux
if hasattr(_psplatform, "disk_swaps"):

def disk_swaps():
"""Enumerate swap partitions and swap files as a list of namedtuples:
- path: the path of the swap partition/file on disk
- total: total swap partition/file size
- used: used swap partition/file size
- fstype (Linux): either "partition" or "swapfile"
- priority (Linux): makes sense when multiple swap files are in
use. The lower the priority, the more likely the swap file is
to be used.
"""
return _psplatform.disk_swaps()

__all__.append("disk_swaps")


# =====================================================================
# --- network related functions
# =====================================================================
Expand Down
2 changes: 2 additions & 0 deletions psutil/_common.py
Expand Up @@ -176,6 +176,8 @@ class BatteryTime(enum.IntEnum):
'read_time', 'write_time'])
# psutil.disk_partitions()
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
# psutil.disk_swaps()
sdiskswap = namedtuple('sdiskswap', ['path', 'total', 'used'])
# psutil.net_io_counters()
snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
'packets_sent', 'packets_recv',
Expand Down
16 changes: 15 additions & 1 deletion psutil/_psbsd.py
Expand Up @@ -202,7 +202,14 @@ def virtual_memory():

def swap_memory():
"""System swap memory as (total, used, free, sin, sout) namedtuple."""
total, used, free, sin, sout = cext.swap_mem()
if OPENBSD:
total = used = sin = sout = 0
for swap in cext.disk_swaps():
total += swap[1]
used += swap[2]
free = total - used
else:
total, used, free, sin, sout = cext.swap_mem()
percent = usage_percent(used, total, round_=1)
return _common.sswap(total, used, free, percent, sin, sout)

Expand Down Expand Up @@ -337,6 +344,13 @@ def disk_partitions(all=False):
disk_usage = _psposix.disk_usage
disk_io_counters = cext.disk_io_counters

# FreeBSD, OpenBSD
if hasattr(cext, "disk_swaps"):

def disk_swaps():
"""Return disk page files information."""
return [_common.sdiskswap(*x) for x in cext.disk_swaps()]


# =====================================================================
# --- network
Expand Down
34 changes: 34 additions & 0 deletions psutil/_pslinux.py
Expand Up @@ -182,6 +182,9 @@ class IOPriority(enum.IntEnum):
'read_time', 'write_time',
'read_merged_count', 'write_merged_count',
'busy_time'])
# psutil.disk_swaps()
sdiskswap = namedtuple(
'sdiskswap', _common.sdiskswap._fields + ('fstype', 'priority'))
# psutil.Process().open_files()
popenfile = namedtuple(
'popenfile', ['path', 'fd', 'position', 'mode', 'flags'])
Expand Down Expand Up @@ -1182,6 +1185,37 @@ def disk_partitions(all=False):
return retlist


def disk_swaps():
"""Return swap partitions (or swap files)."""
retlist = []
try:
f = open_text("%s/swaps" % get_procfs_path())
except FileNotFoundError:
return retlist
else:
with f:
lines = f.readlines()
lines.pop(0) # header
for line in lines:
# Format is confusing:
# Filename Type\tSize Used Priority
# /dev/nvme0n1p3 partition\t11718652 2724 -2
line = line.strip()
name_and_type, _, other_fields = line.partition('\t')
fstype = name_and_type.split()[-1]
# "/dev/nvme0n1p3 partition" -> "/dev/nvme0n1p3"
path = name_and_type.rstrip(fstype).strip()
# The priority column is useful when multiple swap
# files are in use. The lower the priority, the
# more likely the swap file is to be used.
total, used, priority = map(int, other_fields.split('\t'))
total *= 1024
used *= 1024
nt = sdiskswap(path, total, used, fstype, priority)
retlist.append(nt)
return retlist


# =====================================================================
# --- sensors
# =====================================================================
Expand Down
6 changes: 6 additions & 0 deletions psutil/_psutil_bsd.c
Expand Up @@ -965,8 +965,10 @@ static PyMethodDef mod_methods[] = {
"Return number of logical CPUs on the system"},
{"virtual_mem", psutil_virtual_mem, METH_VARARGS,
"Return system virtual memory usage statistics"},
#if !defined(PSUTIL_OPENBSD)
{"swap_mem", psutil_swap_mem, METH_VARARGS,
"Return swap mem stats"},
#endif
{"cpu_times", psutil_cpu_times, METH_VARARGS,
"Return system cpu times as a tuple (user, system, nice, idle, irc)"},
{"per_cpu_times", psutil_per_cpu_times, METH_VARARGS,
Expand All @@ -976,6 +978,10 @@ static PyMethodDef mod_methods[] = {
{"disk_partitions", psutil_disk_partitions, METH_VARARGS,
"Return a list of tuples including device, mount point and "
"fs type for all partitions mounted on the system."},
#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD)
{"disk_swaps", psutil_disk_swaps, METH_VARARGS,
"Enumerate swap partitions/files."},
#endif
{"net_io_counters", psutil_net_io_counters, METH_VARARGS,
"Return dict of tuples of networks I/O information."},
{"disk_io_counters", psutil_disk_io_counters, METH_VARARGS,
Expand Down
2 changes: 2 additions & 0 deletions psutil/_psutil_windows.c
Expand Up @@ -1604,6 +1604,8 @@ PsutilMethods[] = {
"Return a list of currently connected users."},
{"disk_partitions", psutil_disk_partitions, METH_VARARGS,
"Return disk partitions."},
{"disk_swaps", psutil_disk_swaps, METH_VARARGS,
"Return information about the disk page files as a list."},
{"net_connections", psutil_net_connections, METH_VARARGS,
"Return system-wide connections"},
{"net_if_addrs", psutil_net_if_addrs, METH_VARARGS,
Expand Down
17 changes: 17 additions & 0 deletions psutil/_pswindows.py
Expand Up @@ -165,6 +165,9 @@ class IOPriority(enum.IntEnum):
['user', 'system', 'idle', 'interrupt', 'dpc'])
# psutil.virtual_memory()
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
# psutil.disk_swaps()
sdiskswap = namedtuple(
'sdiskswap', _common.sdiskswap._fields + ('peak', ))
# psutil.Process.memory_info()
pmem = namedtuple(
'pmem', ['rss', 'vms',
Expand Down Expand Up @@ -196,6 +199,9 @@ def convert_dos_path(s):
into:
"C:\Windows\systemew\file.txt"
"""
# "\??\" refers to \GLOBAL??\. Just remove it.
if s.startswith("\\??\\"):
return s[4:]
rawdrive = '\\'.join(s.split('\\')[:3])
driveletter = cext.win32_QueryDosDevice(rawdrive)
remainder = s[len(rawdrive):]
Expand Down Expand Up @@ -274,6 +280,17 @@ def disk_partitions(all):
return [_common.sdiskpart(*x) for x in rawlist]


def disk_swaps():
"""Return disk page files information."""
ret = []
rawlist = cext.disk_swaps()
for dospath, total, used, peak in rawlist:
path = convert_dos_path(dospath)
nt = sdiskswap(path, total, used, peak)
ret.append(nt)
return ret


# =====================================================================
# --- CPU
# =====================================================================
Expand Down
68 changes: 68 additions & 0 deletions psutil/arch/freebsd/specific.c
Expand Up @@ -20,6 +20,7 @@
#include <sys/proc.h>
#include <signal.h>
#include <fcntl.h>
#include <paths.h> // _PATH_DEV
#include <sys/vmmeter.h> // needed for vmtotal struct
#include <devstat.h> // for swap mem
#include <libutil.h> // process open files, shared libs (kinfo_getvmmap), cwd
Expand Down Expand Up @@ -1075,3 +1076,70 @@ psutil_cpu_freq(PyObject *self, PyObject *args) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}


#define NSWAP 16

/*
* Enumerate swap locations.
*/
PyObject *
psutil_disk_swaps(PyObject *self, PyObject *args) {
struct kvm_swap ksw;
struct xswdev xsw;
size_t mibsize;
size_t size;
char path[PATH_MAX];
int mib[NSWAP];
int n;
int pagesize = getpagesize();
PyObject *py_tuple = NULL;
PyObject *py_retlist = PyList_New(0);

if (! py_retlist)
return NULL;

mibsize = sizeof(mib) / sizeof(mib[0]);
if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1) {
PyErr_SetFromOSErrnoWithSyscall("sysctlnametomib");
goto error;
}

for (n=0; ; ++n) {
mib[mibsize] = n;
size = sizeof(xsw);

if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1) {
if (errno == ENOENT)
break;
PyErr_SetFromOSErrnoWithSyscall("sysctl");
goto error;
}

if (xsw.xsw_dev == NODEV)
strlcpy(path, "[nodev]", sizeof(path));
else if (xsw.xsw_flags & SWIF_DEV_PREFIX)
strlcpy(path, devname(xsw.xsw_dev, S_IFCHR), sizeof(path));
else
sprintf(path, "%s%s", _PATH_DEV, devname(xsw.xsw_dev, S_IFCHR));

py_tuple = Py_BuildValue(
"(sii)",
path,
xsw.xsw_nblks * pagesize, // total
xsw.xsw_used * pagesize // used
);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_CLEAR(py_tuple);
}

return py_retlist;

error:
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
return NULL;
}
1 change: 1 addition & 0 deletions psutil/arch/freebsd/specific.h
Expand Up @@ -27,6 +27,7 @@ PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
PyObject* psutil_disk_swaps(PyObject* self, PyObject* args);
#if defined(PSUTIL_FREEBSD)
PyObject* psutil_sensors_battery(PyObject* self, PyObject* args);
PyObject* psutil_sensors_cpu_temperature(PyObject* self, PyObject* args);
Expand Down
34 changes: 20 additions & 14 deletions psutil/arch/openbsd/specific.c
Expand Up @@ -355,10 +355,14 @@ psutil_virtual_mem(PyObject *self, PyObject *args) {


PyObject *
psutil_swap_mem(PyObject *self, PyObject *args) {
uint64_t swap_total, swap_free;
psutil_disk_swaps(PyObject *self, PyObject *args) {
struct swapent *swdev;
int nswap, i;
PyObject *py_tuple = NULL;
PyObject *py_retlist = PyList_New(0);

if (! py_retlist)
return NULL;

if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) {
PyErr_SetFromErrno(PyExc_OSError);
Expand All @@ -375,26 +379,28 @@ psutil_swap_mem(PyObject *self, PyObject *args) {
goto error;
}

// Total things up.
swap_total = swap_free = 0;
for (i = 0; i < nswap; i++) {
if (swdev[i].se_flags & SWF_ENABLE) {
swap_free += (swdev[i].se_nblks - swdev[i].se_inuse);
swap_total += swdev[i].se_nblks;
py_tuple = Py_BuildValue(
"(sLL)",
swdev[i].se_path,
swdev[i].se_nblks * DEV_BSIZE, // total
swdev[i].se_inuse * DEV_BSIZE
);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_CLEAR(py_tuple);
}
}

free(swdev);
return Py_BuildValue("(LLLII)",
swap_total * DEV_BSIZE,
(swap_total - swap_free) * DEV_BSIZE,
swap_free * DEV_BSIZE,
// swap in / swap out is not supported as the
// swapent struct does not provide any info
// about it.
0, 0);
return py_retlist;

error:
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
free(swdev);
return NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion psutil/arch/openbsd/specific.h
Expand Up @@ -18,7 +18,7 @@ PyObject * psutil_get_cmdline(pid_t pid);
//
PyObject *psutil_proc_threads(PyObject *self, PyObject *args);
PyObject *psutil_virtual_mem(PyObject *self, PyObject *args);
PyObject *psutil_swap_mem(PyObject *self, PyObject *args);
PyObject *psutil_disk_swaps(PyObject *self, PyObject *args);
PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args);
PyObject *psutil_proc_cwd(PyObject *self, PyObject *args);
PyObject *psutil_proc_connections(PyObject *self, PyObject *args);
Expand Down

0 comments on commit 0396b4a

Please sign in to comment.