Skip to content

Commit

Permalink
AIX: implement num_ctx_switches (#1164)
Browse files Browse the repository at this point in the history
* small changes

* AIX: implement num_ctx_switches
  • Loading branch information
wiggin15 authored and giampaolo committed Oct 31, 2017
1 parent 1781c24 commit 65a5234
Show file tree
Hide file tree
Showing 16 changed files with 185 additions and 89 deletions.
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ include psutil/arch/aix/ifaddrs.c
include psutil/arch/aix/ifaddrs.h
include psutil/arch/aix/net_connections.c
include psutil/arch/aix/net_connections.h
include psutil/arch/aix/common.c
include psutil/arch/aix/common.h
include psutil/arch/aix/net_kernel_structs.h
include psutil/arch/freebsd/proc_socks.c
include psutil/arch/freebsd/proc_socks.h
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1376,7 +1376,7 @@ Process class
The number voluntary and involuntary context switches performed by
this process (cumulative).

Availability: all platforms except AIX
.. versionchanged:: 5.4.1 added AIX support

.. method:: num_fds()

Expand Down
12 changes: 5 additions & 7 deletions psutil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -899,13 +899,11 @@ def num_handles(self):
"""
return self._proc.num_handles()

if hasattr(_psplatform.Process, "num_ctx_switches"):

def num_ctx_switches(self):
"""Return the number of voluntary and involuntary context
switches performed by this process.
"""
return self._proc.num_ctx_switches()
def num_ctx_switches(self):
"""Return the number of voluntary and involuntary context
switches performed by this process.
"""
return self._proc.num_ctx_switches()

def num_threads(self):
"""Return the number of threads used by this process."""
Expand Down
5 changes: 5 additions & 0 deletions psutil/_psaix.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,11 @@ def num_fds(self):
return 0
return len(os.listdir("%s/%s/fd" % (self._procfs_path, 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:
Expand Down
44 changes: 42 additions & 2 deletions psutil/_psutil_aix.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
* All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
/*
*/

/*
* AIX support is experimental at this time.
* The following functions and methods are unsupported on the AIX platform:
* - psutil.Process.memory_maps
* - psutil.Process.num_ctx_switches
*
* Known limitations:
* - psutil.Process.io_counters read count is always 0
* - psutil.Process.threads may not be available on older AIX versions
* - reading basic process info may fail or return incorrect values when
* process is starting (see IBM APAR IV58499 - fixed in newer AIX versions)
* - sockets and pipes may not be counted in num_fds (fixed in newer AIX
Expand Down Expand Up @@ -49,6 +49,7 @@

#include "arch/aix/ifaddrs.h"
#include "arch/aix/net_connections.h"
#include "arch/aix/common.h"
#include "_psutil_common.h"
#include "_psutil_posix.h"

Expand Down Expand Up @@ -307,6 +308,43 @@ psutil_proc_cred(PyObject *self, PyObject *args) {
}


/*
* Return process voluntary and involuntary context switches as a Python tuple.
*/
static PyObject *
psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) {
PyObject *py_tuple = NULL;
pid32_t requested_pid;
pid32_t pid = 0;
int np = 0;
struct procentry64 *processes = (struct procentry64 *)NULL;
struct procentry64 *p;

if (! PyArg_ParseTuple(args, "i", &requested_pid))
return NULL;

processes = psutil_read_process_table(&np);
if (!processes)
return NULL;

/* Loop through processes */
for (p = processes; np > 0; np--, p++) {
pid = p->pi_pid;
if (requested_pid != pid)
continue;
py_tuple = Py_BuildValue("LL",
(long long) p->pi_ru.ru_nvcsw, /* voluntary context switches */
(long long) p->pi_ru.ru_nivcsw); /* involuntary */
free(processes);
return py_tuple;
}

/* finished iteration without finding requested pid */
free(processes);
return NoSuchProcess();
}


/*
* Return users currently connected on the system.
*/
Expand Down Expand Up @@ -833,6 +871,8 @@ PsutilMethods[] =
#endif
{"proc_io_counters", psutil_proc_io_counters, METH_VARARGS,
"Get process I/O counters."},
{"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS,
"Get process I/O counters."},

// --- system-related functions
{"users", psutil_users, METH_VARARGS,
Expand Down
2 changes: 1 addition & 1 deletion psutil/_psutil_sunos.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ psutil_proc_cred(PyObject *self, PyObject *args) {


/*
* Return process uids/gids as a Python tuple.
* Return process voluntary and involuntary context switches as a Python tuple.
*/
static PyObject *
psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) {
Expand Down
79 changes: 79 additions & 0 deletions psutil/arch/aix/common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2017, Arnon Yaari
* 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 <sys/core.h>
#include <stdlib.h>
#include "common.h"

/* psutil_kread() - read from kernel memory */
int
psutil_kread(
int Kd, /* kernel memory file descriptor */
KA_T addr, /* kernel memory address */
char *buf, /* buffer to receive data */
size_t len) { /* length to read */
int br;

if (lseek64(Kd, (off64_t)addr, L_SET) == (off64_t)-1) {
PyErr_SetFromErrno(PyExc_OSError);
return 1;
}
br = read(Kd, buf, len);
if (br == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return 1;
}
if (br != len) {
PyErr_SetString(PyExc_RuntimeError,
"size mismatch when reading kernel memory fd");
return 1;
}
return 0;
}

struct procentry64 *
psutil_read_process_table(int * num) {
size_t msz;
pid32_t pid = 0;
struct procentry64 *processes = (struct procentry64 *)NULL;
struct procentry64 *p;
int Np = 0; /* number of processes allocated in 'processes' */
int np = 0; /* number of processes read into 'processes' */
int i; /* number of processes read in current iteration */

msz = (size_t)(PROCSIZE * PROCINFO_INCR);
processes = (struct procentry64 *)malloc(msz);
if (!processes) {
PyErr_NoMemory();
return NULL;
}
Np = PROCINFO_INCR;
p = processes;
while ((i = getprocs64(p, PROCSIZE, (struct fdsinfo64 *)NULL, 0, &pid,
PROCINFO_INCR))
== PROCINFO_INCR) {
np += PROCINFO_INCR;
if (np >= Np) {
msz = (size_t)(PROCSIZE * (Np + PROCINFO_INCR));
processes = (struct procentry64 *)realloc((char *)processes, msz);
if (!processes) {
PyErr_NoMemory();
return NULL;
}
Np += PROCINFO_INCR;
}
p = (struct procentry64 *)((char *)processes + (np * PROCSIZE));
}

/* add the number of processes read in the last iteration */
if (i > 0)
np += i;

*num = np;
return processes;
}
31 changes: 31 additions & 0 deletions psutil/arch/aix/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2017, Arnon Yaari
* All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/

#ifndef __PSUTIL_AIX_COMMON_H__
#define __PSUTIL_AIX_COMMON_H__

#include <sys/core.h>

#define PROCINFO_INCR (256)
#define PROCSIZE (sizeof(struct procentry64))
#define FDSINFOSIZE (sizeof(struct fdsinfo64))
#define KMEM "/dev/kmem"

typedef u_longlong_t KA_T;

/* psutil_kread() - read from kernel memory */
int psutil_kread(int Kd, /* kernel memory file descriptor */
KA_T addr, /* kernel memory address */
char *buf, /* buffer to receive data */
size_t len); /* length to read */

struct procentry64 *
psutil_read_process_table(
int * num /* out - number of processes read */
);

#endif /* __PSUTIL_AIX_COMMON_H__ */
79 changes: 10 additions & 69 deletions psutil/arch/aix/net_connections.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,57 +13,26 @@
* - dialects/aix/dproc.c:get_kernel_access
*/

#include "net_connections.h"
#include <Python.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#define _KERNEL 1
#define _KERNEL
#include <sys/file.h>
#undef _KERNEL
#include <stdlib.h>
#include <sys/types.h>
#include <sys/core.h>
#include <sys/domain.h>
#include <sys/un.h>
#include <netinet/in_pcb.h>
#include <arpa/inet.h>
#include "net_kernel_structs.h"


#include "../../_psutil_common.h"
#include "net_kernel_structs.h"
#include "net_connections.h"
#include "common.h"

#define PROCINFO_INCR (256)
#define PROCSIZE (sizeof(struct procentry64))
#define FDSINFOSIZE (sizeof(struct fdsinfo64))
#define KMEM "/dev/kmem"
#define NO_SOCKET (PyObject *)(-1)

typedef u_longlong_t KA_T;
static int PSUTIL_CONN_NONE = 128;

/* psutil_kread() - read from kernel memory */
static int
psutil_kread(
int Kd, /* kernel memory file descriptor */
KA_T addr, /* kernel memory address */
char *buf, /* buffer to receive data */
size_t len) { /* length to read */
int br;

if (lseek64(Kd, (off64_t)addr, L_SET) == (off64_t)-1) {
PyErr_SetFromErrno(PyExc_OSError);
return 1;
}
br = read(Kd, buf, len);
if (br == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return 1;
}
if (br != len) {
PyErr_SetString(PyExc_RuntimeError,
"size mismatch when reading kernel memory fd");
return 1;
}
return 0;
}

static int
read_unp_addr(
int Kd,
Expand Down Expand Up @@ -244,10 +213,8 @@ psutil_net_connections(PyObject *self, PyObject *args) {
int i, np;
struct procentry64 *p;
struct fdsinfo64 *fds = (struct fdsinfo64 *)NULL;
size_t msz;
pid32_t requested_pid;
pid32_t pid;
int Np = 0; /* number of processes */
struct procentry64 *processes = (struct procentry64 *)NULL;
/* the process table */

Expand All @@ -262,34 +229,9 @@ psutil_net_connections(PyObject *self, PyObject *args) {
goto error;
}

/* Read the process table */
msz = (size_t)(PROCSIZE * PROCINFO_INCR);
processes = (struct procentry64 *)malloc(msz);
if (!processes) {
PyErr_NoMemory();
processes = psutil_read_process_table(&np);
if (!processes)
goto error;
}
Np = PROCINFO_INCR;
np = pid = 0;
p = processes;
while ((i = getprocs64(p, PROCSIZE, (struct fdsinfo64 *)NULL, 0, &pid,
PROCINFO_INCR))
== PROCINFO_INCR) {
np += PROCINFO_INCR;
if (np >= Np) {
msz = (size_t)(PROCSIZE * (Np + PROCINFO_INCR));
processes = (struct procentry64 *)realloc((char *)processes, msz);
if (!processes) {
PyErr_NoMemory();
goto error;
}
Np += PROCINFO_INCR;
}
p = (struct procentry64 *)((char *)processes + (np * PROCSIZE));
}

if (i > 0)
np += i;

/* Loop through processes */
for (p = processes; np > 0; np--, p++) {
Expand All @@ -299,7 +241,6 @@ psutil_net_connections(PyObject *self, PyObject *args) {
if (p->pi_state == 0 || p->pi_state == SZOMB)
continue;


if (!fds) {
fds = (struct fdsinfo64 *)malloc((size_t)FDSINFOSIZE);
if (!fds) {
Expand Down
5 changes: 5 additions & 0 deletions psutil/arch/aix/net_connections.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
* found in the LICENSE file.
*/

#ifndef __NET_CONNECTIONS_H__
#define __NET_CONNECTIONS_H__

#include <Python.h>

PyObject* psutil_net_connections(PyObject *self, PyObject *args);

#endif /* __NET_CONNECTIONS_H__ */
4 changes: 2 additions & 2 deletions psutil/arch/solaris/v10/ifaddrs.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* Reference: https://lists.samba.org/archive/samba-technical/2009-February/063079.html */


#ifndef __IFADDRS_H___
#define __IFADDRS_H___
#ifndef __IFADDRS_H__
#define __IFADDRS_H__

#include <sys/socket.h>
#include <net/if.h>
Expand Down
Loading

0 comments on commit 65a5234

Please sign in to comment.