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(GetLastError());
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(GetLastError());
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);
}
|