-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
bpo-34060: Report system load when running test suite for Windows #8287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Report system load when running test suite on Windows. Patch by Ammar Askar. | ||
Based on prior work by Jeremy Kloth. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ | |
|
||
#define WINDOWS_LEAN_AND_MEAN | ||
#include "windows.h" | ||
#include <pdh.h> | ||
#include <crtdbg.h> | ||
#include "winreparse.h" | ||
|
||
|
@@ -1699,6 +1700,92 @@ _winapi_GetFileType_impl(PyObject *module, HANDLE handle) | |
return result; | ||
} | ||
|
||
// We use an exponentially weighted moving average, just like Unix systems do | ||
// https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation | ||
// This constant serves as the damping factor. | ||
#define LOADAVG_FACTOR_1F 0.9200444146293232478931553241 | ||
// The time interval in seconds between taking load counts | ||
#define SAMPLING_INTERVAL 5 | ||
|
||
double load_1m = 0; | ||
|
||
VOID CALLBACK LoadCallback(PVOID hCounter) | ||
{ | ||
PDH_FMT_COUNTERVALUE displayValue; | ||
PdhGetFormattedCounterValue((PDH_HCOUNTER) hCounter, PDH_FMT_DOUBLE, 0, &displayValue); | ||
|
||
double currentLoad = displayValue.doubleValue; | ||
double newLoad = load_1m * LOADAVG_FACTOR_1F + currentLoad * (1.0 - LOADAVG_FACTOR_1F); | ||
load_1m = newLoad; | ||
} | ||
|
||
/*[clinic input] | ||
_winapi.GetLoadAvg | ||
|
||
Gets the 1 minute load average (processor queue length) for the system. | ||
|
||
InitializeLoadCounter must be called before this function to engage the | ||
mechanism that records load values. | ||
|
||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
_winapi_GetLoadAvg_impl(PyObject *module) | ||
/*[clinic end generated code: output=e79e25f9f0783a3e input=e874ce4fc553db23]*/ | ||
{ | ||
PyObject* load = PyFloat_FromDouble(load_1m); | ||
return load; | ||
} | ||
|
||
/*[clinic input] | ||
_winapi.InitializeLoadCounter | ||
|
||
Initializes instrumentation code to keep track of system load. | ||
|
||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
_winapi_InitializeLoadCounter_impl(PyObject *module) | ||
/*[clinic end generated code: output=943e4187b2a20b39 input=3caa0958b4abcea0]*/ | ||
{ | ||
PDH_STATUS s; | ||
HQUERY hQuery; | ||
HCOUNTER hCounter; | ||
|
||
if ((s = PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS) | ||
{ | ||
goto WMIerror; | ||
} | ||
|
||
WCHAR *szCounterPath = L"\\System\\Processor Queue Length"; | ||
if ((s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter)) != ERROR_SUCCESS) | ||
{ | ||
goto WMIerror; | ||
} | ||
|
||
HANDLE event = CreateEventW(NULL, FALSE, FALSE, L"LoadUpdateEvent"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hum. It seems like you allocate a resource, but never release it. I would suggest to create an object which keeps track of these resources and release them later. getloadavg() would be a method of that object. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be acceptable to do it in the module's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I dislike using m_free() for that. |
||
if (event == NULL) { | ||
PyErr_SetFromWindowsErr(GetLastError()); | ||
return NULL; | ||
} | ||
|
||
if ((s = PdhCollectQueryDataEx(hQuery, SAMPLING_INTERVAL, event)) != ERROR_SUCCESS) | ||
{ | ||
goto WMIerror; | ||
} | ||
|
||
HANDLE waitHandle; | ||
if (RegisterWaitForSingleObject(&waitHandle, event, (WAITORTIMERCALLBACK) LoadCallback, | ||
(PVOID) hCounter, INFINITE, WT_EXECUTEDEFAULT) == 0) { | ||
PyErr_SetFromWindowsErr(GetLastError()); | ||
return NULL; | ||
} | ||
|
||
Py_RETURN_NONE; | ||
WMIerror: | ||
PyErr_SetExcFromWindowsErr(PyExc_OSError, 0); | ||
return NULL; | ||
} | ||
|
||
static PyMethodDef winapi_functions[] = { | ||
_WINAPI_CLOSEHANDLE_METHODDEF | ||
|
@@ -1727,6 +1814,8 @@ static PyMethodDef winapi_functions[] = { | |
_WINAPI_WRITEFILE_METHODDEF | ||
_WINAPI_GETACP_METHODDEF | ||
_WINAPI_GETFILETYPE_METHODDEF | ||
_WINAPI_GETLOADAVG_METHODDEF | ||
_WINAPI_INITIALIZELOADCOUNTER_METHODDEF | ||
{NULL, NULL} | ||
}; | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move the assignment on a separated line. Same comments for other assignments in if().