1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
|
/*
* 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 related to the Windows Management Instrumentation API.
*/
#include <Python.h>
#include <windows.h>
#include <pdh.h>
#include "../../_psutil_common.h"
// We use an exponentially weighted moving average, just like Unix systems do
// https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation
//
// These constants serve as the damping factor and are calculated with
// 1 / exp(sampling interval in seconds / window size in seconds)
//
// This formula comes from linux's include/linux/sched/loadavg.h
// https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23
#define LOADAVG_FACTOR_1F 0.9200444146293232478931553241
#define LOADAVG_FACTOR_5F 0.9834714538216174894737477501
#define LOADAVG_FACTOR_15F 0.9944598480048967508795473394
// The time interval in seconds between taking load counts, same as Linux
#define SAMPLING_INTERVAL 5
double load_avg_1m = 0;
double load_avg_5m = 0;
double load_avg_15m = 0;
VOID CALLBACK LoadAvgCallback(PVOID hCounter, BOOLEAN timedOut) {
PDH_FMT_COUNTERVALUE displayValue;
double currentLoad;
PDH_STATUS err;
err = PdhGetFormattedCounterValue(
(PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &displayValue);
// Skip updating the load if we can't get the value successfully
if (err != ERROR_SUCCESS) {
return;
}
currentLoad = displayValue.doubleValue;
load_avg_1m = load_avg_1m * LOADAVG_FACTOR_1F + currentLoad * \
(1.0 - LOADAVG_FACTOR_1F);
load_avg_5m = load_avg_5m * LOADAVG_FACTOR_5F + currentLoad * \
(1.0 - LOADAVG_FACTOR_5F);
load_avg_15m = load_avg_15m * LOADAVG_FACTOR_15F + currentLoad * \
(1.0 - LOADAVG_FACTOR_15F);
}
PyObject *
psutil_init_loadavg_counter(PyObject *self, PyObject *args) {
WCHAR *szCounterPath = L"\\System\\Processor Queue Length";
PDH_STATUS s;
BOOL ret;
HQUERY hQuery;
HCOUNTER hCounter;
HANDLE event;
HANDLE waitHandle;
if ((PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS)
goto error;
s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter);
if (s != ERROR_SUCCESS)
goto error;
event = CreateEventW(NULL, FALSE, FALSE, L"LoadUpdateEvent");
if (event == NULL) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
s = PdhCollectQueryDataEx(hQuery, SAMPLING_INTERVAL, event);
if (s != ERROR_SUCCESS)
goto error;
ret = RegisterWaitForSingleObject(
&waitHandle,
event,
(WAITORTIMERCALLBACK)LoadAvgCallback,
(PVOID)
hCounter,
INFINITE,
WT_EXECUTEDEFAULT);
if (ret == 0) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
Py_RETURN_NONE;
error:
PyErr_SetFromWindowsErr(0);
return NULL;
}
/*
* Gets the emulated 1 minute, 5 minute and 15 minute load averages
* (processor queue length) for the system.
* `init_loadavg_counter` must be called before this function to engage the
* mechanism that records load values.
*/
PyObject *
psutil_get_loadavg(PyObject *self, PyObject *args) {
return Py_BuildValue("(ddd)", load_avg_1m, load_avg_5m, load_avg_15m);
}
|