Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions 16 Lib/test/libregrtest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ def __init__(self):
self.next_single_test = None
self.next_single_filename = None

# use the platform specific APIs available
# for system load averages
self.getloadavg = None
try:
import _winapi
_winapi.InitializeLoadCounter()
self.getloadavg = _winapi.GetLoadAvg
except ImportError:
pass
if hasattr(os, 'getloadavg'):
self.getloadavg = lambda: os.getloadavg()[0]

def accumulate_result(self, test, result):
ok, test_time = result
if ok not in (CHILD_ERROR, INTERRUPTED):
Expand Down Expand Up @@ -130,8 +142,8 @@ def display_progress(self, test_index, test):
line = f"[{line}] {test}"

# add the system load prefix: "load avg: 1.80 "
if hasattr(os, 'getloadavg'):
load_avg_1min = os.getloadavg()[0]
if self.getloadavg:
load_avg_1min = self.getloadavg()
line = f"load avg: {load_avg_1min:.2f} {line}"

# add the timestamp prefix: "0:01:05 "
Expand Down
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.
89 changes: 89 additions & 0 deletions 89 Modules/_winapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

#define WINDOWS_LEAN_AND_MEAN
#include "windows.h"
#include <pdh.h>
#include <crtdbg.h>
#include "winreparse.h"

Expand Down Expand Up @@ -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)

Copy link
Copy Markdown
Member

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().

{
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");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be acceptable to do it in the module's m_free function? I was initially thinking of doing something similar but thought that would create a lot of extra code and complexity for an internal API with one use case.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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
Expand Down Expand Up @@ -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}
};

Expand Down
41 changes: 40 additions & 1 deletion 41 Modules/clinic/_winapi.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions 4 PCbuild/pythoncore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
<PreprocessorDefinitions Condition="$(IncludeExternals)">_Py_HAVE_ZLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;Pdh.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
Expand Down Expand Up @@ -461,4 +461,4 @@
<Target Name="_WarnAboutZlib" BeforeTargets="PrepareForBuild" Condition="!$(IncludeExternals)">
<Warning Text="Not including zlib is not a supported configuration." />
</Target>
</Project>
</Project>
Morty Proxy This is a proxified and sanitized view of the page, visit original site.