From 10bb2592484f529cf5a9d926d0546c9bae625aea Mon Sep 17 00:00:00 2001 From: Bernhard Ehlers Date: Sun, 19 Apr 2020 20:42:46 +0200 Subject: [PATCH] Implement a minimum interval between cpu_percent() calls. Fixes #1738 --- .../handlers/api/compute/project_handler.py | 3 +- .../handlers/api/compute/server_handler.py | 3 +- gns3server/notification_queue.py | 4 +- gns3server/utils/cpu_percent.py | 48 +++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 gns3server/utils/cpu_percent.py diff --git a/gns3server/handlers/api/compute/project_handler.py b/gns3server/handlers/api/compute/project_handler.py index fed82210..d8eb0e11 100644 --- a/gns3server/handlers/api/compute/project_handler.py +++ b/gns3server/handlers/api/compute/project_handler.py @@ -25,6 +25,7 @@ import tempfile from gns3server.web.route import Route from gns3server.compute.project_manager import ProjectManager from gns3server.compute import MODULES +from gns3server.utils.cpu_percent import CpuPercent from gns3server.schemas.project import ( PROJECT_OBJECT_SCHEMA, @@ -208,7 +209,7 @@ class ProjectHandler: """ stats = {} # Non blocking call in order to get cpu usage. First call will return 0 - stats["cpu_usage_percent"] = psutil.cpu_percent(interval=None) + stats["cpu_usage_percent"] = CpuPercent.get(interval=None) stats["memory_usage_percent"] = psutil.virtual_memory().percent return {"action": "ping", "event": stats} diff --git a/gns3server/handlers/api/compute/server_handler.py b/gns3server/handlers/api/compute/server_handler.py index 4f043f95..c158a55d 100644 --- a/gns3server/handlers/api/compute/server_handler.py +++ b/gns3server/handlers/api/compute/server_handler.py @@ -23,6 +23,7 @@ from gns3server.config import Config from gns3server.schemas.version import VERSION_SCHEMA from gns3server.schemas.server_statistics import SERVER_STATISTICS_SCHEMA from gns3server.compute.port_manager import PortManager +from gns3server.utils.cpu_percent import CpuPercent from gns3server.version import __version__ from aiohttp.web import HTTPConflict from psutil._common import bytes2human @@ -57,7 +58,7 @@ class ServerHandler: swap_total = psutil.swap_memory().total swap_free = psutil.swap_memory().free swap_used = psutil.swap_memory().used - cpu_percent = int(psutil.cpu_percent()) + cpu_percent = int(CpuPercent.get()) load_average_percent = [int(x / psutil.cpu_count() * 100) for x in psutil.getloadavg()] memory_percent = int(psutil.virtual_memory().percent) swap_percent = int(psutil.swap_memory().percent) diff --git a/gns3server/notification_queue.py b/gns3server/notification_queue.py index a3eab916..d81a2a2b 100644 --- a/gns3server/notification_queue.py +++ b/gns3server/notification_queue.py @@ -19,6 +19,8 @@ import asyncio import json import psutil +from gns3server.utils.cpu_percent import CpuPercent + class NotificationQueue(asyncio.Queue): """ @@ -51,7 +53,7 @@ class NotificationQueue(asyncio.Queue): """ msg = {} # Non blocking call in order to get cpu usage. First call will return 0 - msg["cpu_usage_percent"] = psutil.cpu_percent(interval=None) + msg["cpu_usage_percent"] = CpuPercent.get(interval=None) msg["memory_usage_percent"] = psutil.virtual_memory().percent return msg diff --git a/gns3server/utils/cpu_percent.py b/gns3server/utils/cpu_percent.py new file mode 100644 index 00000000..441b7efb --- /dev/null +++ b/gns3server/utils/cpu_percent.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import psutil +import time + + +class CpuPercent: + """ + Ensures a minumum interval between two cpu_percent() calls + """ + + _last_measurement = None # time of last measurement + _last_cpu_percent = 0.0 # last cpu_percent + + @classmethod + def get(cls, interval=None): + """ + Get CPU utilization as a percentage + + :returns: float + """ + + if interval: + cls._last_cpu_percent = psutil.cpu_percent(interval=interval) + cls._last_measurement = time.monotonic() + else: + cur_time = time.monotonic() + if cls._last_measurement is None or \ + (cur_time - cls._last_measurement) >= 1.9: + cls._last_cpu_percent = psutil.cpu_percent(interval=None) + cls._last_measurement = cur_time + + return cls._last_cpu_percent