Skip to content

Commit

Permalink
Merge branch 'oneshot' into oneshot-win
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Oct 28, 2016
2 parents c373045 + a63974f commit 7818a81
Show file tree
Hide file tree
Showing 3 changed files with 356 additions and 253 deletions.
127 changes: 45 additions & 82 deletions psutil/_psutil_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,57 +766,6 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) {
}


/*
* Alternative implementation of the one above but bypasses ACCESS DENIED.
*/
static PyObject *
psutil_proc_memory_info_2(PyObject *self, PyObject *args) {
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
SIZE_T private;
unsigned long pfault_count;

#if defined(_WIN64)
unsigned long long m1, m2, m3, m4, m5, m6, m7, m8;
#else
unsigned int m1, m2, m3, m4, m5, m6, m7, m8;
#endif

if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (! psutil_get_proc_info(pid, &process, &buffer))
return NULL;

#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2
private = process->PrivatePageCount;
#else
private = 0;
#endif
pfault_count = process->PageFaultCount;

m1 = process->PeakWorkingSetSize;
m2 = process->WorkingSetSize;
m3 = process->QuotaPeakPagedPoolUsage;
m4 = process->QuotaPagedPoolUsage;
m5 = process->QuotaPeakNonPagedPoolUsage;
m6 = process->QuotaNonPagedPoolUsage;
m7 = process->PagefileUsage;
m8 = process->PeakPagefileUsage;

free(buffer);

// SYSTEM_PROCESS_INFORMATION values are defined as SIZE_T which on 64
// bits is an (unsigned long long) and on 32bits is an (unsigned int).
// "_WIN64" is defined if we're running a 64bit Python interpreter not
// exclusively if the *system* is 64bit.
#if defined(_WIN64)
return Py_BuildValue("(kKKKKKKKKK)",
#else
return Py_BuildValue("(kIIIIIIIII)",
#endif
pfault_count, m1, m2, m3, m4, m5, m6, m7, m8, private);
}

/**
* Returns the USS of the process.
Expand Down Expand Up @@ -2742,34 +2691,32 @@ psutil_proc_num_handles(PyObject *self, PyObject *args) {
* denied. This is slower because it iterates over all processes.
* Returned tuple includes the following process info:
*
* - num_threads
* - ctx_switches
* - num_handles (fallback)
* - user/kernel times (fallback)
* - create time (fallback)
* - io counters (fallback)
* - num_threads()
* - ctx_switches()
* - num_handles() (fallback)
* - cpu_times() (fallback)
* - create_time() (fallback)
* - io_counters() (fallback)
* - memory_info() (fallback)
*/
static PyObject *
psutil_proc_info(PyObject *self, PyObject *args) {
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
ULONG num_handles;
ULONG i;
ULONG ctx_switches = 0;
double user_time;
double kernel_time;
long long create_time;
int num_threads;
LONGLONG io_rcount, io_wcount, io_rbytes, io_wbytes;

SIZE_T mem_private;
PyObject *py_retlist;

if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (! psutil_get_proc_info(pid, &process, &buffer))
return NULL;

num_handles = process->HandleCount;
for (i = 0; i < process->NumberOfThreads; i++)
ctx_switches += process->Threads[i].ContextSwitches;
user_time = (double)process->UserTime.HighPart * 429.4967296 + \
Expand All @@ -2788,26 +2735,44 @@ psutil_proc_info(PyObject *self, PyObject *args) {
create_time += process->CreateTime.LowPart - 116444736000000000LL;
create_time /= 10000000;
}
num_threads = (int)process->NumberOfThreads;
io_rcount = process->ReadOperationCount.QuadPart;
io_wcount = process->WriteOperationCount.QuadPart;
io_rbytes = process->ReadTransferCount.QuadPart;
io_wbytes = process->WriteTransferCount.QuadPart;
free(buffer);

return Py_BuildValue(
"kkdddiKKKK",
num_handles,
ctx_switches,
user_time,
kernel_time,
(double)create_time,
num_threads,
io_rcount,
io_wcount,
io_rbytes,
io_wbytes
#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2
mem_private = process->PrivatePageCount;
#else
mem_private = 0;
#endif

py_retlist = Py_BuildValue(
#if defined(_WIN64)
"kkdddiKKKK" "kKKKKKKKKK",
#else
"kkdddiKKKK" "kIIIIIIIII",
#endif
process->HandleCount, // num handles
ctx_switches, // num ctx switches
user_time, // cpu user time
kernel_time, // cpu kernel time
(double)create_time, // create time
(int)process->NumberOfThreads, // num threads
process->ReadOperationCount.QuadPart, // io rcount
process->WriteOperationCount.QuadPart, // io wcount
process->ReadTransferCount.QuadPart, // io rbytes
process->WriteTransferCount.QuadPart, // io wbytes
// memory
process->PageFaultCount, // num page faults
process->PeakWorkingSetSize, // peak wset
process->WorkingSetSize, // wset
process->QuotaPeakPagedPoolUsage, // peak paged pool
process->QuotaPagedPoolUsage, // paged pool
process->QuotaPeakNonPagedPoolUsage, // peak non paged pool
process->QuotaNonPagedPoolUsage, // non paged pool
process->PagefileUsage, // pagefile
process->PeakPagefileUsage, // peak pagefile
mem_private // private
);

free(buffer);
return py_retlist;
}


Expand Down Expand Up @@ -3420,8 +3385,6 @@ PsutilMethods[] = {
"seconds since the epoch"},
{"proc_memory_info", psutil_proc_memory_info, METH_VARARGS,
"Return a tuple of process memory information"},
{"proc_memory_info_2", psutil_proc_memory_info_2, METH_VARARGS,
"Alternate implementation"},
{"proc_memory_uss", psutil_proc_memory_uss, METH_VARARGS,
"Return the USS of the process"},
{"proc_cwd", psutil_proc_cwd, METH_VARARGS,
Expand Down
67 changes: 58 additions & 9 deletions psutil/_pswindows.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,29 @@ class Priority(enum.IntEnum):

globals().update(Priority.__members__)

pinfo_map = dict(
num_handles=0,
ctx_switches=1,
user_time=2,
kernel_time=3,
create_time=4,
num_threads=5,
io_rcount=6,
io_wcount=7,
io_rbytes=8,
io_wbytes=9,
num_page_faults=10,
peak_wset=11,
wset=12,
peak_paged_pool=13,
paged_pool=14,
peak_non_paged_pool=15,
non_paged_pool=16,
pagefile=17,
peak_pagefile=18,
mem_private=19,
)


# =====================================================================
# --- named tuples
Expand Down Expand Up @@ -589,6 +612,14 @@ def handle_ctx(self):
if not self._inctx:
cext.win32_CloseHandle(handle)

def oneshot_info(self):
"""Return multiple information about this process as a
raw tuple.
"""
ret = cext.proc_info(self.pid)
assert len(ret) == len(pinfo_map)
return ret

@wrap_exceptions
def name(self):
"""Return process name, which on Windows is always the final
Expand Down Expand Up @@ -646,7 +677,19 @@ def _get_raw_meminfo(self):
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)
info = self.oneshot_info()
return (
info[pinfo_map['num_page_faults']],
info[pinfo_map['peak_wset']],
info[pinfo_map['wset']],
info[pinfo_map['peak_paged_pool']],
info[pinfo_map['paged_pool']],
info[pinfo_map['peak_non_paged_pool']],
info[pinfo_map['non_paged_pool']],
info[pinfo_map['pagefile']],
info[pinfo_map['peak_pagefile']],
info[pinfo_map['mem_private']],
)
raise

@wrap_exceptions
Expand Down Expand Up @@ -717,12 +760,12 @@ def create_time(self):
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
return self.oneshot_info()[pinfo_map['create_time']]
raise

@wrap_exceptions
def num_threads(self):
return ntpinfo(*cext.proc_info(self.pid)).num_threads
return self.oneshot_info()[pinfo_map['num_threads']]

@wrap_exceptions
def threads(self):
Expand All @@ -740,8 +783,9 @@ def cpu_times(self):
user, system = cext.proc_cpu_times(self.pid, handle)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
nt = ntpinfo(*cext.proc_info(self.pid))
user, system = (nt.user_time, nt.kernel_time)
info = self.oneshot_info()
user = info[pinfo_map['user_time']]
system = info[pinfo_map['kernel_time']]
else:
raise
# Children user/system times are not retrievable (set to 0).
Expand Down Expand Up @@ -823,8 +867,13 @@ def io_counters(self):
ret = cext.proc_io_counters(self.pid, handle)
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)
info = self.oneshot_info()
ret = (
info[pinfo_map['io_rcount']],
info[pinfo_map['io_wcount']],
info[pinfo_map['io_rbytes']],
info[pinfo_map['io_wbytes']],
)
else:
raise
return _common.pio(*ret)
Expand Down Expand Up @@ -877,11 +926,11 @@ def num_handles(self):
return cext.proc_num_handles(self.pid, handle)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
return ntpinfo(*cext.proc_info(self.pid)).num_handles
return self.oneshot_info()[pinfo_map['num_handles']]
raise

@wrap_exceptions
def num_ctx_switches(self):
ctx_switches = ntpinfo(*cext.proc_info(self.pid)).ctx_switches
ctx_switches = self.oneshot_info()[pinfo_map['ctx_switches']]
# only voluntary ctx switches are supported
return _common.pctxsw(ctx_switches, 0)
Loading

0 comments on commit 7818a81

Please sign in to comment.