From bc2cd4be7b465edfc3df2497f4622b2e0dc00066 Mon Sep 17 00:00:00 2001 From: Lars Holmberg Date: Wed, 6 Apr 2022 10:38:25 +0200 Subject: [PATCH 1/3] Add cpu_warning event, so listeners can do some action (typically logging) when CPU usage is too high. --- locust/event.py | 5 +++++ locust/runners.py | 13 ++++++++----- locust/test/test_runners.py | 7 +++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/locust/event.py b/locust/event.py index edfdbd6c09..679936bd0f 100644 --- a/locust/event.py +++ b/locust/event.py @@ -207,6 +207,11 @@ class Events: Fired when the Reset Stats button is clicked in the web UI. """ + cpu_warning: EventHook + """ + Fired when the CPU usage exceeds runners.CPU_WARNING_THRESHOLD (90% by default) + """ + def __init__(self): # For backwarde compatibility use also values of class attributes for name, value in vars(type(self)).items(): diff --git a/locust/runners.py b/locust/runners.py index 3a3d04eeaa..350c17370d 100644 --- a/locust/runners.py +++ b/locust/runners.py @@ -56,6 +56,7 @@ ] WORKER_REPORT_INTERVAL = 3.0 CPU_MONITOR_INTERVAL = 5.0 +CPU_WARNING_THRESHOLD = 90 HEARTBEAT_INTERVAL = 1 HEARTBEAT_LIVENESS = 3 HEARTBEAT_DEAD_INTERNAL = -60 @@ -288,11 +289,13 @@ def monitor_cpu_and_memory(self): while True: self.current_cpu_usage = process.cpu_percent() self.current_memory_usage = process.memory_info().rss - if self.current_cpu_usage > 90 and not self.cpu_warning_emitted: - logging.warning( - "CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-locust-distributed.html for how to distribute the load over multiple CPU cores or machines" - ) - self.cpu_warning_emitted = True + if self.current_cpu_usage > CPU_WARNING_THRESHOLD: + self.environment.events.cpu_warning.fire(environment=self.environment) + if not self.cpu_warning_emitted: + logging.warning( + f"CPU usage above {CPU_WARNING_THRESHOLD}%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-locust-distributed.html for how to distribute the load over multiple CPU cores or machines" + ) + self.cpu_warning_emitted = True gevent.sleep(CPU_MONITOR_INTERVAL) def start(self, user_count: int, spawn_rate: float, wait: bool = False): diff --git a/locust/test/test_runners.py b/locust/test/test_runners.py index f0f259c730..c0cf5ae4e1 100644 --- a/locust/test/test_runners.py +++ b/locust/test/test_runners.py @@ -144,10 +144,17 @@ def cpu_task(self): _ = 3 / 2 environment = Environment(user_classes=[CpuUser]) + environment._cpu_warning_event_triggered = False + + def cpu_warning(environment, **kwargs): + environment._cpu_warning_event_triggered = True + + environment.events.cpu_warning.add_listener(cpu_warning) runner = LocalRunner(environment) self.assertFalse(runner.cpu_warning_emitted) runner.spawn_users({CpuUser.__name__: 1}, wait=False) sleep(2.5) + self.assertTrue(environment._cpu_warning_event_triggered) runner.quit() self.assertTrue(runner.cpu_warning_emitted) finally: From 61078d37f832c3a4952c2e28a2bd1be645d79f17 Mon Sep 17 00:00:00 2001 From: Lars Holmberg Date: Wed, 6 Apr 2022 10:42:45 +0200 Subject: [PATCH 2/3] Pass actual cpu usage to cpu_warning event --- locust/runners.py | 2 +- locust/test/test_runners.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/locust/runners.py b/locust/runners.py index 350c17370d..40b82c14cf 100644 --- a/locust/runners.py +++ b/locust/runners.py @@ -290,7 +290,7 @@ def monitor_cpu_and_memory(self): self.current_cpu_usage = process.cpu_percent() self.current_memory_usage = process.memory_info().rss if self.current_cpu_usage > CPU_WARNING_THRESHOLD: - self.environment.events.cpu_warning.fire(environment=self.environment) + self.environment.events.cpu_warning.fire(cpu_usage=self.current_cpu_usage, environment=self.environment) if not self.cpu_warning_emitted: logging.warning( f"CPU usage above {CPU_WARNING_THRESHOLD}%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-locust-distributed.html for how to distribute the load over multiple CPU cores or machines" diff --git a/locust/test/test_runners.py b/locust/test/test_runners.py index c0cf5ae4e1..031f1bec6c 100644 --- a/locust/test/test_runners.py +++ b/locust/test/test_runners.py @@ -146,8 +146,9 @@ def cpu_task(self): environment = Environment(user_classes=[CpuUser]) environment._cpu_warning_event_triggered = False - def cpu_warning(environment, **kwargs): + def cpu_warning(environment, cpu_usage, **kwargs): environment._cpu_warning_event_triggered = True + environment._cpu_usage = cpu_usage environment.events.cpu_warning.add_listener(cpu_warning) runner = LocalRunner(environment) @@ -155,6 +156,7 @@ def cpu_warning(environment, **kwargs): runner.spawn_users({CpuUser.__name__: 1}, wait=False) sleep(2.5) self.assertTrue(environment._cpu_warning_event_triggered) + self.assertGreater(environment._cpu_usage, 90) runner.quit() self.assertTrue(runner.cpu_warning_emitted) finally: From 3f5f599d2e6a1d890620d70e0f78d13c3443babf Mon Sep 17 00:00:00 2001 From: Lars Holmberg Date: Wed, 6 Apr 2022 12:45:25 +0200 Subject: [PATCH 3/3] cpu_warning event: environment argument first, because that is the way others order it... --- locust/runners.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locust/runners.py b/locust/runners.py index 40b82c14cf..ac01dbbc59 100644 --- a/locust/runners.py +++ b/locust/runners.py @@ -290,7 +290,7 @@ def monitor_cpu_and_memory(self): self.current_cpu_usage = process.cpu_percent() self.current_memory_usage = process.memory_info().rss if self.current_cpu_usage > CPU_WARNING_THRESHOLD: - self.environment.events.cpu_warning.fire(cpu_usage=self.current_cpu_usage, environment=self.environment) + self.environment.events.cpu_warning.fire(environment=self.environment, cpu_usage=self.current_cpu_usage) if not self.cpu_warning_emitted: logging.warning( f"CPU usage above {CPU_WARNING_THRESHOLD}%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-locust-distributed.html for how to distribute the load over multiple CPU cores or machines"