From 36dc5711a86b14839aa277af87b9f81a2422d765 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 21 Oct 2022 09:45:03 -0700 Subject: [PATCH 01/19] Handle mismatch between committed vs. used physical memory Signed-off-by: Daniel Widdis --- psutil/_pswindows.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 3802f3edb0..e89bbbf1c0 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -251,7 +251,12 @@ def swap_memory(): # system memory (commit total/limit) is the sum of physical and swap # thus physical memory values need to be substracted to get swap values total = total_system - total_phys - free = min(total, free_system - free_phys) + # commit total is incremented immediately (decrementing free_system) + # while the corresponding free physical value is not decremented until + # pages are accessed, so free_phys is an overestimate of the portion + # free_system contributed to by physical memory, and in some edge cases + # can exceed free system memory. + free = max(0, free_system - free_phys) used = total - free percent = usage_percent(used, total, round_=1) return _common.sswap(total, used, free, percent, 0, 0) From 975ef956495c6553f35f03fa18958bc0e455c77e Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 21 Oct 2022 11:07:38 -0700 Subject: [PATCH 02/19] Add tests Signed-off-by: Daniel Widdis --- CREDITS | 2 +- HISTORY.rst | 2 ++ psutil/_pswindows.py | 2 +- psutil/tests/test_windows.py | 24 ++++++++++++++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index f414636087..c845a8c661 100644 --- a/CREDITS +++ b/CREDITS @@ -804,7 +804,7 @@ I: 2150 N: Daniel Widdis W: https://github.com/dbwiddis -I: 2077 +I: 2077, 2160 N: Amir Rossert W: https://github.com/arossert diff --git a/HISTORY.rst b/HISTORY.rst index ac50e89792..605e85257e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -45,6 +45,8 @@ ``SPEED_UNKNOWN`` definition. (patch by Amir Rossert) - 2010_, [macOS]: on MacOS, arm64 ``IFM_1000_TX`` and ``IFM_1000_T`` are the same value, causing a build failure. (patch by Lawrence D'Anna) +- 2160_, [Windows]: Handle mismatch between committed vs. used physical memory. + (patch by Daniel Widdis) 5.9.3 ===== diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index e89bbbf1c0..7453f99abd 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -256,7 +256,7 @@ def swap_memory(): # pages are accessed, so free_phys is an overestimate of the portion # free_system contributed to by physical memory, and in some edge cases # can exceed free system memory. - free = max(0, free_system - free_phys) + free = max(0, min(total, free_system - free_phys)) used = total - free percent = usage_percent(used, total, round_=1) return _common.sswap(total, used, free, percent, 0, 0) diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 9b163a185f..f1fde37a50 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -161,6 +161,30 @@ def test_free_phymem(self): self.assertAlmostEqual( int(w.AvailableBytes), psutil.virtual_memory().free, delta=TOLERANCE_SYS_MEM) + def test_total_swapmem(self): + if (psutil.swap_memory().total > 0): + w = wmi.WMI().Win32_PerfRawData_PerfOS_Memory()[0] + self.assertEqual(int(w.CommitLimit) + - psutil.virtual_memory().total, + psutil.swap_memory().total) + else: + self.assertEqual(0, psutil.swap_memory().total) + self.assertEqual(0, psutil.swap_memory().free) + self.assertEqual(0, psutil.swap_memory().used) + + def test_percent_swapmem(self): + if (psutil.swap_memory().total > 0): + w = wmi.WMI().Win32_PerfRawData_PerfOS_PagingFile()[0] + # calculate swap usage to integer percent + percentSwap = int(w.PercentUsage) * 100 / int(w.PercentUsage_Base) + # exact percent may change but should be reasonable + # assert within +/- 10% and between 0 and 100 + self.assertGreaterEqual(psutil.swap_memory().percent, 0) + self.assertGreaterEqual(psutil.swap_memory().percent, + percentSwap - 10) + self.assertLessEqual(psutil.swap_memory().percent, + percentSwap + 10) + self.assertLessEqual(psutil.swap_memory().percent, 100) # @unittest.skipIf(wmi is None, "wmi module is not installed") # def test__UPTIME(self): From b86a5dca4674b28bddb1fe476a0196e97d9198b3 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Fri, 21 Oct 2022 11:34:55 -0700 Subject: [PATCH 03/19] add windows test for free physical mem #2074 Signed-off-by: Daniel Widdis --- psutil/tests/test_windows.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index f1fde37a50..8e3247280e 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -23,6 +23,7 @@ import psutil from psutil import WINDOWS from psutil._compat import FileNotFoundError +from psutil._compat import which from psutil._compat import super from psutil._compat import which from psutil.tests import APPVEYOR @@ -161,6 +162,7 @@ def test_free_phymem(self): self.assertAlmostEqual( int(w.AvailableBytes), psutil.virtual_memory().free, delta=TOLERANCE_SYS_MEM) + def test_total_swapmem(self): if (psutil.swap_memory().total > 0): w = wmi.WMI().Win32_PerfRawData_PerfOS_Memory()[0] From efe7fb4c86c403affa107c1d0a3702684f8156af Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 21 Oct 2022 11:53:26 -0700 Subject: [PATCH 04/19] Remove unneeded conditional Signed-off-by: Daniel Widdis --- psutil/tests/test_windows.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 8e3247280e..1d3f1a7dcb 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -164,13 +164,10 @@ def test_free_phymem(self): delta=TOLERANCE_SYS_MEM) def test_total_swapmem(self): - if (psutil.swap_memory().total > 0): - w = wmi.WMI().Win32_PerfRawData_PerfOS_Memory()[0] - self.assertEqual(int(w.CommitLimit) - - psutil.virtual_memory().total, - psutil.swap_memory().total) - else: - self.assertEqual(0, psutil.swap_memory().total) + w = wmi.WMI().Win32_PerfRawData_PerfOS_Memory()[0] + self.assertEqual(int(w.CommitLimit) - psutil.virtual_memory().total, + psutil.swap_memory().total) + if (psutil.swap_memory().total == 0): self.assertEqual(0, psutil.swap_memory().free) self.assertEqual(0, psutil.swap_memory().used) @@ -185,7 +182,7 @@ def test_percent_swapmem(self): self.assertGreaterEqual(psutil.swap_memory().percent, percentSwap - 10) self.assertLessEqual(psutil.swap_memory().percent, - percentSwap + 10) + percentSwap + 10) self.assertLessEqual(psutil.swap_memory().percent, 100) # @unittest.skipIf(wmi is None, "wmi module is not installed") From d9abb863c6c1314b7422074aa64bd56109ed5c81 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 21 Oct 2022 12:13:32 -0700 Subject: [PATCH 05/19] Use AssertAlmostEqual for percentage range Signed-off-by: Daniel Widdis --- psutil/tests/test_windows.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 1d3f1a7dcb..7d1f2c4ec4 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -179,10 +179,8 @@ def test_percent_swapmem(self): # exact percent may change but should be reasonable # assert within +/- 10% and between 0 and 100 self.assertGreaterEqual(psutil.swap_memory().percent, 0) - self.assertGreaterEqual(psutil.swap_memory().percent, - percentSwap - 10) - self.assertLessEqual(psutil.swap_memory().percent, - percentSwap + 10) + self.assertAlmostEqual(psutil.swap_memory().percent, percentSwap, + delta=10) self.assertLessEqual(psutil.swap_memory().percent, 100) # @unittest.skipIf(wmi is None, "wmi module is not installed") From 5ccbead7c9e1b73d858935cee0d4e92e6ca602b5 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 21 Oct 2022 14:23:09 -0700 Subject: [PATCH 06/19] Fetch percent swap from PDH Signed-off-by: Daniel Widdis --- psutil/_psutil_windows.c | 1 + psutil/_pswindows.py | 12 +++---- psutil/arch/windows/wmi.c | 65 ++++++++++++++++++++++++++++++++++-- psutil/arch/windows/wmi.h | 1 + psutil/tests/test_windows.py | 10 ++++-- 5 files changed, 78 insertions(+), 11 deletions(-) diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c index 2ed937ee95..f4bca00100 100644 --- a/psutil/_psutil_windows.c +++ b/psutil/_psutil_windows.c @@ -1560,6 +1560,7 @@ PsutilMethods[] = { {"disk_usage", psutil_disk_usage, METH_VARARGS}, {"getloadavg", (PyCFunction)psutil_get_loadavg, METH_VARARGS}, {"getpagesize", psutil_getpagesize, METH_VARARGS}, + {"getpercentswap", (PyCFunction)psutil_get_loadavg, METH_VARARGS}, {"init_loadavg_counter", (PyCFunction)psutil_init_loadavg_counter, METH_VARARGS}, {"net_connections", psutil_net_connections, METH_VARARGS}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS}, diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 7453f99abd..6993b7652a 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -244,20 +244,18 @@ def swap_memory(): mem = cext.virtual_mem() total_phys = mem[0] - free_phys = mem[1] total_system = mem[2] - free_system = mem[3] # system memory (commit total/limit) is the sum of physical and swap # thus physical memory values need to be substracted to get swap values total = total_system - total_phys # commit total is incremented immediately (decrementing free_system) # while the corresponding free physical value is not decremented until - # pages are accessed, so free_phys is an overestimate of the portion - # free_system contributed to by physical memory, and in some edge cases - # can exceed free system memory. - free = max(0, min(total, free_system - free_phys)) - used = total - free + # pages are accessed, so we ignore free system memory and calculate + # page file usage based on performance counter + percentswap = cext.percentswap() + used = int(percentswap * total) + free = total - used percent = usage_percent(used, total, round_=1) return _common.sswap(total, used, free, percent, 0, 0) diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c index fc7a66529e..464161e576 100644 --- a/psutil/arch/windows/wmi.c +++ b/psutil/arch/windows/wmi.c @@ -3,7 +3,8 @@ * 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. + * Functions related to the Performance Data Helper (PDH) API. + * File name from Windows Management Instrumentation API, not implemented. */ #include @@ -12,6 +13,9 @@ #include "../../_psutil_common.h" +/* + * Load average implementation using "\System\Processor Queue Length" counter + */ // We use an exponentially weighted moving average, just like Unix systems do // https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation @@ -53,7 +57,6 @@ VOID CALLBACK LoadAvgCallback(PVOID hCounter, BOOLEAN timedOut) { (1.0 - LOADAVG_FACTOR_15F); } - PyObject * psutil_init_loadavg_counter(PyObject *self, PyObject *args) { WCHAR *szCounterPath = L"\\System\\Processor Queue Length"; @@ -118,3 +121,61 @@ PyObject * psutil_get_loadavg(PyObject *self, PyObject *args) { return Py_BuildValue("(ddd)", load_avg_1m, load_avg_5m, load_avg_15m); } + +/* + * Percent swap implementation using "\PagingFile(_Total)\% Usage" counter + */ + +/* + * Return a Python float representing the percent usage of all paging files on + * the system. + */ +PyObject * +psutil_get_percentswap(PyObject *self, PyObject *args) { + WCHAR *szCounterPath = L"\\PagingFile(_Total)\\% Usage"; + PDH_STATUS s; + HQUERY hQuery; + HCOUNTER hCounter; + PDH_FMT_COUNTERVALUE counterValue; + double percentUsage; + + if ((PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS) { + PyErr_Format(PyExc_RuntimeError, "PdhOpenQueryW failed"); + return NULL; + } + + s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter); + if (s != ERROR_SUCCESS) { + PyErr_Format( + PyExc_RuntimeError, + "PdhAddEnglishCounterW failed. Performance counters may be disabled." + ); + return NULL; + } + + s = PdhCollectQueryData(hQuery); + if (s != ERROR_SUCCESS) { + PyErr_Format(PyExc_RuntimeError, "PdhCollectQueryData failed"); + return NULL; + } + + s = PdhGetFormattedCounterValue( + (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &counterValue); + if (s != ERROR_SUCCESS) { + return NULL; + } + + percentUsage = counterValue.doubleValue; + + if ((PdhRemoveCounter(hCounter)) != ERROR_SUCCESS) { + PyErr_Format(PyExc_RuntimeError, "PdhRemoveCounter failed"); + return NULL; + } + + if ((PdhCloseQuery(hQuery)) != ERROR_SUCCESS) { + PyErr_Format(PyExc_RuntimeError, "PdhCloseQuery failed"); + return NULL; + } + + return Py_BuildValue("d", percentUsage); +} diff --git a/psutil/arch/windows/wmi.h b/psutil/arch/windows/wmi.h index 311242a393..c93411077e 100644 --- a/psutil/arch/windows/wmi.h +++ b/psutil/arch/windows/wmi.h @@ -8,3 +8,4 @@ PyObject* psutil_init_loadavg_counter(); PyObject* psutil_get_loadavg(); +PyObject* psutil_get_percentswap(); diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 7d1f2c4ec4..097474cd14 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -177,10 +177,16 @@ def test_percent_swapmem(self): # calculate swap usage to integer percent percentSwap = int(w.PercentUsage) * 100 / int(w.PercentUsage_Base) # exact percent may change but should be reasonable - # assert within +/- 10% and between 0 and 100 + # assert within +/- 5% and between 0 and 100 + # check the pdh class + self.assertGreaterEqual(psutil.percentswap(), 0) + self.assertAlmostEqual(psutil.percentswap(), percentSwap, + delta=5) + self.assertLessEqual(psutil.percentswap(), 100) + # check the end result self.assertGreaterEqual(psutil.swap_memory().percent, 0) self.assertAlmostEqual(psutil.swap_memory().percent, percentSwap, - delta=10) + delta=5) self.assertLessEqual(psutil.swap_memory().percent, 100) # @unittest.skipIf(wmi is None, "wmi module is not installed") From 5bc70cae1ece14ff77b08f38a600f2344f6a4c6d Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 21 Oct 2022 15:47:35 -0700 Subject: [PATCH 07/19] Fix function naming and counter string Signed-off-by: Daniel Widdis --- psutil/_psutil_windows.c | 2 +- psutil/_pswindows.py | 2 +- psutil/arch/windows/wmi.c | 2 +- psutil/tests/test_windows.py | 6 ------ 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c index f4bca00100..99c631c2bd 100644 --- a/psutil/_psutil_windows.c +++ b/psutil/_psutil_windows.c @@ -1560,7 +1560,7 @@ PsutilMethods[] = { {"disk_usage", psutil_disk_usage, METH_VARARGS}, {"getloadavg", (PyCFunction)psutil_get_loadavg, METH_VARARGS}, {"getpagesize", psutil_getpagesize, METH_VARARGS}, - {"getpercentswap", (PyCFunction)psutil_get_loadavg, METH_VARARGS}, + {"getpercentswap", (PyCFunction)psutil_get_percentswap, METH_VARARGS}, {"init_loadavg_counter", (PyCFunction)psutil_init_loadavg_counter, METH_VARARGS}, {"net_connections", psutil_net_connections, METH_VARARGS}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS}, diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 6993b7652a..b07e6f68fa 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -253,7 +253,7 @@ def swap_memory(): # while the corresponding free physical value is not decremented until # pages are accessed, so we ignore free system memory and calculate # page file usage based on performance counter - percentswap = cext.percentswap() + percentswap = cext.getpercentswap() used = int(percentswap * total) free = total - used percent = usage_percent(used, total, round_=1) diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c index 464161e576..ec083642c6 100644 --- a/psutil/arch/windows/wmi.c +++ b/psutil/arch/windows/wmi.c @@ -132,7 +132,7 @@ psutil_get_loadavg(PyObject *self, PyObject *args) { */ PyObject * psutil_get_percentswap(PyObject *self, PyObject *args) { - WCHAR *szCounterPath = L"\\PagingFile(_Total)\\% Usage"; + WCHAR *szCounterPath = L"\\Paging File(_Total)\\% Usage"; PDH_STATUS s; HQUERY hQuery; HCOUNTER hCounter; diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 097474cd14..0d8265230d 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -178,12 +178,6 @@ def test_percent_swapmem(self): percentSwap = int(w.PercentUsage) * 100 / int(w.PercentUsage_Base) # exact percent may change but should be reasonable # assert within +/- 5% and between 0 and 100 - # check the pdh class - self.assertGreaterEqual(psutil.percentswap(), 0) - self.assertAlmostEqual(psutil.percentswap(), percentSwap, - delta=5) - self.assertLessEqual(psutil.percentswap(), 100) - # check the end result self.assertGreaterEqual(psutil.swap_memory().percent, 0) self.assertAlmostEqual(psutil.swap_memory().percent, percentSwap, delta=5) From 9b355d0eb71fab8d6c89e3b436971cff9c9a9536 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 21 Oct 2022 16:09:05 -0700 Subject: [PATCH 08/19] Change PR title and update HISTORY Signed-off-by: Daniel Widdis --- HISTORY.rst | 2 +- psutil/arch/windows/wmi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 605e85257e..6f2028bd1d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -45,7 +45,7 @@ ``SPEED_UNKNOWN`` definition. (patch by Amir Rossert) - 2010_, [macOS]: on MacOS, arm64 ``IFM_1000_TX`` and ``IFM_1000_T`` are the same value, causing a build failure. (patch by Lawrence D'Anna) -- 2160_, [Windows]: Handle mismatch between committed vs. used physical memory. +- 2160_, [Windows]: Get Windows percent swap usage from performance counters. (patch by Daniel Widdis) 5.9.3 diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c index ec083642c6..44e694812a 100644 --- a/psutil/arch/windows/wmi.c +++ b/psutil/arch/windows/wmi.c @@ -123,7 +123,7 @@ psutil_get_loadavg(PyObject *self, PyObject *args) { } /* - * Percent swap implementation using "\PagingFile(_Total)\% Usage" counter + * Percent swap implementation using "\Paging File(_Total)\% Usage" counter */ /* From 660e408a6a9bd5bd9dc709c1cd9e08a9cbcd9ae7 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 21 Oct 2022 16:42:54 -0700 Subject: [PATCH 09/19] Filter WMI Paging File test query to _Total Signed-off-by: Daniel Widdis --- psutil/tests/test_windows.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 0d8265230d..6c8665269e 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -173,7 +173,8 @@ def test_total_swapmem(self): def test_percent_swapmem(self): if (psutil.swap_memory().total > 0): - w = wmi.WMI().Win32_PerfRawData_PerfOS_PagingFile()[0] + w = wmi.WMI().Win32_PerfRawData_PerfOS_PagingFile( + Name="_Total")[0] # calculate swap usage to integer percent percentSwap = int(w.PercentUsage) * 100 / int(w.PercentUsage_Base) # exact percent may change but should be reasonable From 6dc64c46ad970fe278008c77607a3839f4186807 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sat, 22 Oct 2022 08:56:10 -0700 Subject: [PATCH 10/19] Convert percentages to fractions Signed-off-by: Daniel Widdis --- psutil/_pswindows.py | 2 +- psutil/tests/test_windows.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index b07e6f68fa..33075ce369 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -254,7 +254,7 @@ def swap_memory(): # pages are accessed, so we ignore free system memory and calculate # page file usage based on performance counter percentswap = cext.getpercentswap() - used = int(percentswap * total) + used = int(0.01 * percentswap * total) free = total - used percent = usage_percent(used, total, round_=1) return _common.sswap(total, used, free, percent, 0, 0) diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 6c8665269e..bb33aa15d4 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -176,13 +176,13 @@ def test_percent_swapmem(self): w = wmi.WMI().Win32_PerfRawData_PerfOS_PagingFile( Name="_Total")[0] # calculate swap usage to integer percent - percentSwap = int(w.PercentUsage) * 100 / int(w.PercentUsage_Base) + percentSwap = float(w.PercentUsage) / float(w.PercentUsage_Base) # exact percent may change but should be reasonable # assert within +/- 5% and between 0 and 100 - self.assertGreaterEqual(psutil.swap_memory().percent, 0) + self.assertGreaterEqual(psutil.swap_memory().percent, 0.0) self.assertAlmostEqual(psutil.swap_memory().percent, percentSwap, - delta=5) - self.assertLessEqual(psutil.swap_memory().percent, 100) + delta=0.05) + self.assertLessEqual(psutil.swap_memory().percent, 1.0) # @unittest.skipIf(wmi is None, "wmi module is not installed") # def test__UPTIME(self): From 5d3575b94bae9754d6bec9fa2d61851ac5c7f4c5 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sat, 22 Oct 2022 09:49:41 -0700 Subject: [PATCH 11/19] Handle disabled swap/counter failure case Signed-off-by: Daniel Widdis --- psutil/_pswindows.py | 11 +++++++---- psutil/arch/windows/wmi.c | 30 ++++++++++++------------------ 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 33075ce369..15c356944f 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -251,10 +251,13 @@ def swap_memory(): total = total_system - total_phys # commit total is incremented immediately (decrementing free_system) # while the corresponding free physical value is not decremented until - # pages are accessed, so we ignore free system memory and calculate - # page file usage based on performance counter - percentswap = cext.getpercentswap() - used = int(0.01 * percentswap * total) + # pages are accessed, so we can't use free system memory for swap. + # instead, we calculate page file usage based on performance counter + if (total > 0): + percentswap = cext.getpercentswap() + used = int(0.01 * percentswap * total) + else: + used = 0 free = total - used percent = usage_percent(used, total, round_=1) return _common.sswap(total, used, free, percent, 0, 0) diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c index 44e694812a..f4a248163e 100644 --- a/psutil/arch/windows/wmi.c +++ b/psutil/arch/windows/wmi.c @@ -155,27 +155,21 @@ psutil_get_percentswap(PyObject *self, PyObject *args) { s = PdhCollectQueryData(hQuery); if (s != ERROR_SUCCESS) { - PyErr_Format(PyExc_RuntimeError, "PdhCollectQueryData failed"); - return NULL; - } - - s = PdhGetFormattedCounterValue( - (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &counterValue); - if (s != ERROR_SUCCESS) { - return NULL; + // If swap disabled this will fail + percentUsage = 0; + } else { + s = PdhGetFormattedCounterValue( + (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &counterValue); + if (s != ERROR_SUCCESS) { + percentUsage = 0; + } else { + percentUsage = counterValue.doubleValue; + } } - percentUsage = counterValue.doubleValue; + PdhRemoveCounter(hCounter); - if ((PdhRemoveCounter(hCounter)) != ERROR_SUCCESS) { - PyErr_Format(PyExc_RuntimeError, "PdhRemoveCounter failed"); - return NULL; - } - - if ((PdhCloseQuery(hQuery)) != ERROR_SUCCESS) { - PyErr_Format(PyExc_RuntimeError, "PdhCloseQuery failed"); - return NULL; - } + PdhCloseQuery(hQuery); return Py_BuildValue("d", percentUsage); } From 0b0ad4964286c2a2e7e925d6a1a0b0841d4ee0b9 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sat, 22 Oct 2022 10:34:40 -0700 Subject: [PATCH 12/19] Put unit test back to percent Signed-off-by: Daniel Widdis --- psutil/tests/test_windows.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index bb33aa15d4..1d972deb48 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -175,14 +175,14 @@ def test_percent_swapmem(self): if (psutil.swap_memory().total > 0): w = wmi.WMI().Win32_PerfRawData_PerfOS_PagingFile( Name="_Total")[0] - # calculate swap usage to integer percent - percentSwap = float(w.PercentUsage) / float(w.PercentUsage_Base) + # calculate swap usage to percent + percentSwap = int(w.PercentUsage) * 100 / int(w.PercentUsage_Base) # exact percent may change but should be reasonable - # assert within +/- 5% and between 0 and 100 - self.assertGreaterEqual(psutil.swap_memory().percent, 0.0) + # assert within +/- 5% and between 0 and 100% + self.assertGreaterEqual(psutil.swap_memory().percent, 0) self.assertAlmostEqual(psutil.swap_memory().percent, percentSwap, - delta=0.05) - self.assertLessEqual(psutil.swap_memory().percent, 1.0) + delta=5) + self.assertLessEqual(psutil.swap_memory().percent, 100) # @unittest.skipIf(wmi is None, "wmi module is not installed") # def test__UPTIME(self): From aa910e23bf994b851ff6ba46a4215a3fb9abeaf1 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 11 Apr 2023 20:22:01 -0700 Subject: [PATCH 13/19] Rename psutil_get_swappercent to psutil_swap_percent Signed-off-by: Daniel Widdis --- psutil/_psutil_windows.c | 2 +- psutil/arch/windows/wmi.c | 3 ++- psutil/arch/windows/wmi.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c index 99c631c2bd..201878f134 100644 --- a/psutil/_psutil_windows.c +++ b/psutil/_psutil_windows.c @@ -1560,7 +1560,7 @@ PsutilMethods[] = { {"disk_usage", psutil_disk_usage, METH_VARARGS}, {"getloadavg", (PyCFunction)psutil_get_loadavg, METH_VARARGS}, {"getpagesize", psutil_getpagesize, METH_VARARGS}, - {"getpercentswap", (PyCFunction)psutil_get_percentswap, METH_VARARGS}, + {"getpercentswap", (PyCFunction)psutil_swap_percent, METH_VARARGS}, {"init_loadavg_counter", (PyCFunction)psutil_init_loadavg_counter, METH_VARARGS}, {"net_connections", psutil_net_connections, METH_VARARGS}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS}, diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c index f4a248163e..1ed890f73c 100644 --- a/psutil/arch/windows/wmi.c +++ b/psutil/arch/windows/wmi.c @@ -131,7 +131,7 @@ psutil_get_loadavg(PyObject *self, PyObject *args) { * the system. */ PyObject * -psutil_get_percentswap(PyObject *self, PyObject *args) { +psutil_swap_percent(PyObject *self, PyObject *args) { WCHAR *szCounterPath = L"\\Paging File(_Total)\\% Usage"; PDH_STATUS s; HQUERY hQuery; @@ -146,6 +146,7 @@ psutil_get_percentswap(PyObject *self, PyObject *args) { s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter); if (s != ERROR_SUCCESS) { + PdhCloseQuery(hQuery); PyErr_Format( PyExc_RuntimeError, "PdhAddEnglishCounterW failed. Performance counters may be disabled." diff --git a/psutil/arch/windows/wmi.h b/psutil/arch/windows/wmi.h index c93411077e..00461a20d8 100644 --- a/psutil/arch/windows/wmi.h +++ b/psutil/arch/windows/wmi.h @@ -8,4 +8,4 @@ PyObject* psutil_init_loadavg_counter(); PyObject* psutil_get_loadavg(); -PyObject* psutil_get_percentswap(); +PyObject* psutil_swap_percent(); From e3ce8a387015335eb59ca55ee481a91e1dac0605 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 11 Apr 2023 20:50:04 -0700 Subject: [PATCH 14/19] Move psutil_percent_swap to mem.c Signed-off-by: Daniel Widdis --- psutil/arch/windows/mem.c | 50 ++++++++++++++++++++++++++++++++++++ psutil/arch/windows/mem.h | 1 + psutil/arch/windows/wmi.c | 53 --------------------------------------- psutil/arch/windows/wmi.h | 1 - 4 files changed, 51 insertions(+), 54 deletions(-) diff --git a/psutil/arch/windows/mem.c b/psutil/arch/windows/mem.c index 18b535e6af..c676cea3c9 100644 --- a/psutil/arch/windows/mem.c +++ b/psutil/arch/windows/mem.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "../../_psutil_common.h" @@ -41,3 +42,52 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { totalSys, availSys); } + +/* + * Return a Python float representing the percent usage of all paging files on + * the system. + */ +PyObject * +psutil_swap_percent(PyObject *self, PyObject *args) { + WCHAR *szCounterPath = L"\\Paging File(_Total)\\% Usage"; + PDH_STATUS s; + HQUERY hQuery; + HCOUNTER hCounter; + PDH_FMT_COUNTERVALUE counterValue; + double percentUsage; + + if ((PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS) { + PyErr_Format(PyExc_RuntimeError, "PdhOpenQueryW failed"); + return NULL; + } + + s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter); + if (s != ERROR_SUCCESS) { + PdhCloseQuery(hQuery); + PyErr_Format( + PyExc_RuntimeError, + "PdhAddEnglishCounterW failed. Performance counters may be disabled." + ); + return NULL; + } + + s = PdhCollectQueryData(hQuery); + if (s != ERROR_SUCCESS) { + // If swap disabled this will fail + percentUsage = 0; + } else { + s = PdhGetFormattedCounterValue( + (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &counterValue); + if (s != ERROR_SUCCESS) { + percentUsage = 0; + } else { + percentUsage = counterValue.doubleValue; + } + } + + PdhRemoveCounter(hCounter); + + PdhCloseQuery(hQuery); + + return Py_BuildValue("d", percentUsage); +} diff --git a/psutil/arch/windows/mem.h b/psutil/arch/windows/mem.h index a10781dfce..48d3dadee6 100644 --- a/psutil/arch/windows/mem.h +++ b/psutil/arch/windows/mem.h @@ -8,3 +8,4 @@ PyObject *psutil_getpagesize(PyObject *self, PyObject *args); PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); +PyObject *psutil_swap_percent(PyObject *self, PyObject *args); diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c index 1ed890f73c..e4db99954e 100644 --- a/psutil/arch/windows/wmi.c +++ b/psutil/arch/windows/wmi.c @@ -121,56 +121,3 @@ PyObject * psutil_get_loadavg(PyObject *self, PyObject *args) { return Py_BuildValue("(ddd)", load_avg_1m, load_avg_5m, load_avg_15m); } - -/* - * Percent swap implementation using "\Paging File(_Total)\% Usage" counter - */ - -/* - * Return a Python float representing the percent usage of all paging files on - * the system. - */ -PyObject * -psutil_swap_percent(PyObject *self, PyObject *args) { - WCHAR *szCounterPath = L"\\Paging File(_Total)\\% Usage"; - PDH_STATUS s; - HQUERY hQuery; - HCOUNTER hCounter; - PDH_FMT_COUNTERVALUE counterValue; - double percentUsage; - - if ((PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS) { - PyErr_Format(PyExc_RuntimeError, "PdhOpenQueryW failed"); - return NULL; - } - - s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter); - if (s != ERROR_SUCCESS) { - PdhCloseQuery(hQuery); - PyErr_Format( - PyExc_RuntimeError, - "PdhAddEnglishCounterW failed. Performance counters may be disabled." - ); - return NULL; - } - - s = PdhCollectQueryData(hQuery); - if (s != ERROR_SUCCESS) { - // If swap disabled this will fail - percentUsage = 0; - } else { - s = PdhGetFormattedCounterValue( - (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &counterValue); - if (s != ERROR_SUCCESS) { - percentUsage = 0; - } else { - percentUsage = counterValue.doubleValue; - } - } - - PdhRemoveCounter(hCounter); - - PdhCloseQuery(hQuery); - - return Py_BuildValue("d", percentUsage); -} diff --git a/psutil/arch/windows/wmi.h b/psutil/arch/windows/wmi.h index 00461a20d8..311242a393 100644 --- a/psutil/arch/windows/wmi.h +++ b/psutil/arch/windows/wmi.h @@ -8,4 +8,3 @@ PyObject* psutil_init_loadavg_counter(); PyObject* psutil_get_loadavg(); -PyObject* psutil_swap_percent(); From 9d12ff514586a08b19241074fdefa29c4dbb1473 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 11 Apr 2023 20:56:20 -0700 Subject: [PATCH 15/19] Remove duplicate import from rebase Signed-off-by: Daniel Widdis --- psutil/tests/test_windows.py | 1 - 1 file changed, 1 deletion(-) diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 1d972deb48..a9f6893364 100755 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -23,7 +23,6 @@ import psutil from psutil import WINDOWS from psutil._compat import FileNotFoundError -from psutil._compat import which from psutil._compat import super from psutil._compat import which from psutil.tests import APPVEYOR From 06ebf96591b2f1bdbb003a1aea48c52b881b3a6f Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 11 Apr 2023 21:01:55 -0700 Subject: [PATCH 16/19] Revert all changes to wmi.c Signed-off-by: Daniel Widdis --- psutil/arch/windows/wmi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c index e4db99954e..fc7a66529e 100644 --- a/psutil/arch/windows/wmi.c +++ b/psutil/arch/windows/wmi.c @@ -3,8 +3,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * - * Functions related to the Performance Data Helper (PDH) API. - * File name from Windows Management Instrumentation API, not implemented. + * Functions related to the Windows Management Instrumentation API. */ #include @@ -13,9 +12,6 @@ #include "../../_psutil_common.h" -/* - * Load average implementation using "\System\Processor Queue Length" counter - */ // We use an exponentially weighted moving average, just like Unix systems do // https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation @@ -57,6 +53,7 @@ VOID CALLBACK LoadAvgCallback(PVOID hCounter, BOOLEAN timedOut) { (1.0 - LOADAVG_FACTOR_15F); } + PyObject * psutil_init_loadavg_counter(PyObject *self, PyObject *args) { WCHAR *szCounterPath = L"\\System\\Processor Queue Length"; From 58f462bd69727ede9c142c8786c7e924fcea7dfd Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Wed, 12 Apr 2023 23:44:15 -0700 Subject: [PATCH 17/19] Rename getpercentswap to swap_percent Signed-off-by: Daniel Widdis --- psutil/_psutil_windows.c | 2 +- psutil/_pswindows.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c index 201878f134..11176de738 100644 --- a/psutil/_psutil_windows.c +++ b/psutil/_psutil_windows.c @@ -1560,7 +1560,7 @@ PsutilMethods[] = { {"disk_usage", psutil_disk_usage, METH_VARARGS}, {"getloadavg", (PyCFunction)psutil_get_loadavg, METH_VARARGS}, {"getpagesize", psutil_getpagesize, METH_VARARGS}, - {"getpercentswap", (PyCFunction)psutil_swap_percent, METH_VARARGS}, + {"swap_percent", psutil_swap_percent, METH_VARARGS}, {"init_loadavg_counter", (PyCFunction)psutil_init_loadavg_counter, METH_VARARGS}, {"net_connections", psutil_net_connections, METH_VARARGS}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS}, diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 15c356944f..4081aa17fb 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -254,12 +254,12 @@ def swap_memory(): # pages are accessed, so we can't use free system memory for swap. # instead, we calculate page file usage based on performance counter if (total > 0): - percentswap = cext.getpercentswap() + percentswap = cext.swap_percent() used = int(0.01 * percentswap * total) else: used = 0 free = total - used - percent = usage_percent(used, total, round_=1) + percent = round(percentswap, 1) return _common.sswap(total, used, free, percent, 0, 0) From 82abe0c4e1642fb75dbd87e34c46c3e84fb63544 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 13 Apr 2023 09:45:07 +0200 Subject: [PATCH 18/19] Update mem.c --- psutil/arch/windows/mem.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/psutil/arch/windows/mem.c b/psutil/arch/windows/mem.c index c676cea3c9..497399aa91 100644 --- a/psutil/arch/windows/mem.c +++ b/psutil/arch/windows/mem.c @@ -43,10 +43,9 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { availSys); } -/* - * Return a Python float representing the percent usage of all paging files on - * the system. - */ + +// Return a float representing the percent usage of all paging files on +// the system. PyObject * psutil_swap_percent(PyObject *self, PyObject *args) { WCHAR *szCounterPath = L"\\Paging File(_Total)\\% Usage"; @@ -73,21 +72,21 @@ psutil_swap_percent(PyObject *self, PyObject *args) { s = PdhCollectQueryData(hQuery); if (s != ERROR_SUCCESS) { - // If swap disabled this will fail + // If swap disabled this will fail. percentUsage = 0; - } else { + } + else { s = PdhGetFormattedCounterValue( (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &counterValue); if (s != ERROR_SUCCESS) { percentUsage = 0; - } else { + } + else { percentUsage = counterValue.doubleValue; } } PdhRemoveCounter(hCounter); - PdhCloseQuery(hQuery); - return Py_BuildValue("d", percentUsage); } From 49ef9718e0d9ead1def7b95acfbface874ff2baa Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 13 Apr 2023 09:57:36 +0200 Subject: [PATCH 19/19] Update mem.c fail if PdhGetFormattedCounterValue fails --- psutil/arch/windows/mem.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/psutil/arch/windows/mem.c b/psutil/arch/windows/mem.c index 497399aa91..24dc15ad0e 100644 --- a/psutil/arch/windows/mem.c +++ b/psutil/arch/windows/mem.c @@ -44,7 +44,7 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { } -// Return a float representing the percent usage of all paging files on +// Return a float representing the percent usage of all paging files on // the system. PyObject * psutil_swap_percent(PyObject *self, PyObject *args) { @@ -73,17 +73,19 @@ psutil_swap_percent(PyObject *self, PyObject *args) { s = PdhCollectQueryData(hQuery); if (s != ERROR_SUCCESS) { // If swap disabled this will fail. + psutil_debug("PdhCollectQueryData failed; assume swap percent is 0"); percentUsage = 0; - } + } else { s = PdhGetFormattedCounterValue( (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &counterValue); if (s != ERROR_SUCCESS) { - percentUsage = 0; - } - else { - percentUsage = counterValue.doubleValue; + PdhCloseQuery(hQuery); + PyErr_Format( + PyExc_RuntimeError, "PdhGetFormattedCounterValue failed"); + return NULL; } + percentUsage = counterValue.doubleValue; } PdhRemoveCounter(hCounter);