From ead77f0d1f4f2b751d69c18ea065ff310ac5df98 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sun, 1 Nov 2026 01:38:52 +0100 Subject: [PATCH] fix(monitor): stop intel_gpu_top leaving a process on every GPU reading --- AppImage/scripts/flask_server.py | 4 +-- .../tests/test_intel_gpu_top_process.py | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 AppImage/scripts/tests/test_intel_gpu_top_process.py diff --git a/AppImage/scripts/flask_server.py b/AppImage/scripts/flask_server.py index a90a6b47..de42aa2a 100644 --- a/AppImage/scripts/flask_server.py +++ b/AppImage/scripts/flask_server.py @@ -7998,7 +7998,8 @@ def get_detailed_gpu_info(gpu): env = os.environ.copy() env['TERM'] = 'xterm' # Ensure terminal type is set - cmd = f'{intel_gpu_top_path} -J' # Use the found path + # Without a shell: the signal has to reach intel_gpu_top itself. + cmd = [intel_gpu_top_path, '-J'] # print(f"[v0] Executing command: {cmd}", flush=True) pass @@ -8008,7 +8009,6 @@ def get_detailed_gpu_info(gpu): stderr=subprocess.PIPE, text=True, bufsize=1, - shell=True, env=env, cwd='/' # Ejecutar desde root en lugar de dentro del AppImage ) diff --git a/AppImage/scripts/tests/test_intel_gpu_top_process.py b/AppImage/scripts/tests/test_intel_gpu_top_process.py new file mode 100644 index 00000000..314b024d --- /dev/null +++ b/AppImage/scripts/tests/test_intel_gpu_top_process.py @@ -0,0 +1,31 @@ +"""intel_gpu_top runs until it is told to stop, so the Monitor has to hold the +process itself: with a shell in between the signal never reaches it.""" +import ast +import unittest +from pathlib import Path + +SOURCE = Path(__file__).resolve().parents[1] / 'flask_server.py' + + +class IntelGpuTopProcess(unittest.TestCase): + def setUp(self): + tree = ast.parse(SOURCE.read_text(encoding='utf-8')) + self.function = next(node for node in ast.walk(tree) if isinstance(node, ast.FunctionDef) + and node.name == 'get_detailed_gpu_info') + + def test_no_process_of_the_gpu_sampling_goes_through_a_shell(self): + calls = [node for node in ast.walk(self.function) if isinstance(node, ast.Call) + and isinstance(node.func, ast.Attribute) and node.func.attr == 'Popen'] + self.assertTrue(calls) + for call in calls: + self.assertNotIn('shell', [keyword.arg for keyword in call.keywords]) + + def test_the_command_is_a_list(self): + assigned = [node.value for node in ast.walk(self.function) if isinstance(node, ast.Assign) + and any(isinstance(target, ast.Name) and target.id == 'cmd' for target in node.targets)] + self.assertTrue(assigned) + self.assertFalse([value for value in assigned if isinstance(value, ast.JoinedStr)]) + + +if __name__ == '__main__': + unittest.main()