From 32dcaa949d780284e9f8d1fcf249310094f4b728 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 11 Oct 2024 16:07:43 +0200 Subject: msg/async/Event{Poll,Epoll}: move timeout calculation to Timeout.h This is duplicate code, and it's buggy, but I want to fix only one copy. Signed-off-by: Max Kellermann --- src/msg/async/EventEpoll.cc | 4 ++-- src/msg/async/EventPoll.cc | 7 +++---- src/msg/async/Timeout.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 src/msg/async/Timeout.h diff --git a/src/msg/async/EventEpoll.cc b/src/msg/async/EventEpoll.cc index 7ed5321dcda..eb04e3b8e98 100644 --- a/src/msg/async/EventEpoll.cc +++ b/src/msg/async/EventEpoll.cc @@ -17,6 +17,7 @@ #include "common/errno.h" #include #include "EventEpoll.h" +#include "Timeout.h" #define dout_subsys ceph_subsys_ms @@ -120,8 +121,7 @@ int EpollDriver::event_wait(std::vector &fired_events, struct ti { int retval, numevents = 0; - retval = epoll_wait(epfd, events, nevent, - tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1); + retval = epoll_wait(epfd, events, nevent, timeout_to_milliseconds(tvp)); if (retval > 0) { numevents = retval; fired_events.resize(numevents); diff --git a/src/msg/async/EventPoll.cc b/src/msg/async/EventPoll.cc index 4c09dbb4db4..f46528715e3 100644 --- a/src/msg/async/EventPoll.cc +++ b/src/msg/async/EventPoll.cc @@ -15,6 +15,7 @@ #include "common/errno.h" #include "EventPoll.h" +#include "Timeout.h" #include #define dout_subsys ceph_subsys_ms @@ -161,11 +162,9 @@ int PollDriver::event_wait(std::vector &fired_events, struct timeval *tvp) { int retval, numevents = 0; #ifdef _WIN32 - retval = WSAPoll(pfds, max_pfds, - tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1); + retval = WSAPoll(pfds, max_pfds, timeout_to_milliseconds(tvp)); #else - retval = poll(pfds, max_pfds, - tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1); + retval = poll(pfds, max_pfds, timeout_to_milliseconds(tvp)); #endif if (retval > 0) { for (int j = 0; j < max_pfds; j++) { diff --git a/src/msg/async/Timeout.h b/src/msg/async/Timeout.h new file mode 100644 index 00000000000..b47bcec8447 --- /dev/null +++ b/src/msg/async/Timeout.h @@ -0,0 +1,44 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2024 IONOS SE + * + * Author: Max Kellermann + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef CEPH_MSG_TIMEOUT_H +#define CEPH_MSG_TIMEOUT_H + +#include // for struct timeval + +/** + * Convert the given `struct timeval` to milliseconds. + * + * This is supposed to be used as timeout parameter to system calls + * such as poll() and epoll_wait(). + */ +constexpr int +timeout_to_milliseconds(const struct timeval &tv) noexcept +{ + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +/** + * This overload makes the timeout optional; on nullptr, it returns + * -1. + */ +constexpr int +timeout_to_milliseconds(const struct timeval *tv) noexcept +{ + return tv != nullptr ? timeout_to_milliseconds(*tv) : -1; +} + +#endif -- cgit v1.2.3 From c2d192f527ba2ada103a3c3234f90c1e30118d98 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 11 Oct 2024 16:15:28 +0200 Subject: msg/async/Timeout: always round up Currently, we always round down, which has a bad side effect: when a timer comes closer, we have lots of early wakeups, and eventually we'll run into a busy loop (timeout=0) when the timeout is less than one millisecond; the process will remain this busy loop for one millisecond, wasting lots of CPU time. Signed-off-by: Max Kellermann --- src/msg/async/Timeout.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/msg/async/Timeout.h b/src/msg/async/Timeout.h index b47bcec8447..b8df1b40761 100644 --- a/src/msg/async/Timeout.h +++ b/src/msg/async/Timeout.h @@ -17,6 +17,8 @@ #ifndef CEPH_MSG_TIMEOUT_H #define CEPH_MSG_TIMEOUT_H +#include "include/intarith.h" // for div_round_up() + #include // for struct timeval /** @@ -28,7 +30,8 @@ constexpr int timeout_to_milliseconds(const struct timeval &tv) noexcept { - return tv.tv_sec * 1000 + tv.tv_usec / 1000; + /* round up to the next millisecond so we don't wake up too early */ + return tv.tv_sec * 1000 + div_round_up(tv.tv_usec, 1000); } /** -- cgit v1.2.3