From 7c58a81f724d0d939d53a7f9599bb7db47f7c3a4 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Fri, 8 Apr 2022 11:30:48 +0200 Subject: [PATCH] Multiplexer: Take the maximum number of events as a hint This allows indicating the maximum number of events we want to process in a single run, which is usually bounded by the number of file descriptors we are planning on watching. The default is still 1024 events, but this change makes it possible to allocate a smaller vector of events to reduce the memory usage when we know we are going to need to process so many events in a single run. --- pdns/devpollmplexer.cc | 2 +- pdns/epollmplexer.cc | 19 ++++++++----------- pdns/kqueuemplexer.cc | 17 +++++++---------- pdns/mplexer.hh | 8 ++++++-- pdns/pollmplexer.cc | 10 +++++----- pdns/portsmplexer.cc | 15 ++++++--------- pdns/recursordist/rec-main.cc | 2 +- pdns/test-mplexer.cc | 4 ++-- 8 files changed, 36 insertions(+), 41 deletions(-) diff --git a/pdns/devpollmplexer.cc b/pdns/devpollmplexer.cc index 37a0d487ff..071ee9e945 100644 --- a/pdns/devpollmplexer.cc +++ b/pdns/devpollmplexer.cc @@ -62,7 +62,7 @@ private: int d_devpollfd; }; -static FDMultiplexer* makeDevPoll() +static FDMultiplexer* makeDevPoll(unsigned int) { return new DevPollFDMultiplexer(); } diff --git a/pdns/epollmplexer.cc b/pdns/epollmplexer.cc index 85158d246f..74de2c2960 100644 --- a/pdns/epollmplexer.cc +++ b/pdns/epollmplexer.cc @@ -36,7 +36,7 @@ class EpollFDMultiplexer : public FDMultiplexer { public: - EpollFDMultiplexer(); + EpollFDMultiplexer(unsigned int maxEventsHint); ~EpollFDMultiplexer() { if (d_epollfd >= 0) { @@ -59,12 +59,11 @@ public: private: int d_epollfd; std::vector d_eevents; - static int s_maxevents; // not a hard maximum }; -static FDMultiplexer* makeEpoll() +static FDMultiplexer* makeEpoll(unsigned int maxEventsHint) { - return new EpollFDMultiplexer(); + return new EpollFDMultiplexer(maxEventsHint); } static struct EpollRegisterOurselves @@ -75,12 +74,10 @@ static struct EpollRegisterOurselves } } doItEpoll; -int EpollFDMultiplexer::s_maxevents = 1024; - -EpollFDMultiplexer::EpollFDMultiplexer() : - d_eevents(s_maxevents) +EpollFDMultiplexer::EpollFDMultiplexer(unsigned int maxEventsHint) : + d_eevents(maxEventsHint) { - d_epollfd = epoll_create(s_maxevents); // not hard max + d_epollfd = epoll_create(static_cast(maxEventsHint)); // not hard max, just a hint that is actually ignored since Linux 2.6.8 if (d_epollfd < 0) { throw FDMultiplexerException("Setting up epoll: " + stringerror()); } @@ -156,7 +153,7 @@ void EpollFDMultiplexer::alterFD(int fd, FDMultiplexer::EventKind, FDMultiplexer void EpollFDMultiplexer::getAvailableFDs(std::vector& fds, int timeout) { - int ret = epoll_wait(d_epollfd, d_eevents.data(), s_maxevents, timeout); + int ret = epoll_wait(d_epollfd, d_eevents.data(), d_eevents.size(), timeout); if (ret < 0 && errno != EINTR) { throw FDMultiplexerException("epoll returned error: " + stringerror()); @@ -173,7 +170,7 @@ int EpollFDMultiplexer::run(struct timeval* now, int timeout) throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); } - int ret = epoll_wait(d_epollfd, d_eevents.data(), s_maxevents, timeout); + int ret = epoll_wait(d_epollfd, d_eevents.data(), d_eevents.size(), timeout); gettimeofday(now, nullptr); // MANDATORY if (ret < 0 && errno != EINTR) { diff --git a/pdns/kqueuemplexer.cc b/pdns/kqueuemplexer.cc index f777b80808..2c426a69c7 100644 --- a/pdns/kqueuemplexer.cc +++ b/pdns/kqueuemplexer.cc @@ -38,7 +38,7 @@ class KqueueFDMultiplexer : public FDMultiplexer { public: - KqueueFDMultiplexer(); + KqueueFDMultiplexer(unsigned int maxEventsHint); ~KqueueFDMultiplexer() { if (d_kqueuefd >= 0) { @@ -60,14 +60,11 @@ public: private: int d_kqueuefd; std::vector d_kevents; - static unsigned int s_maxevents; // not a hard maximum }; -unsigned int KqueueFDMultiplexer::s_maxevents = 1024; - -static FDMultiplexer* make() +static FDMultiplexer* make(unsigned int maxEventsHint) { - return new KqueueFDMultiplexer(); + return new KqueueFDMultiplexer(maxEventsHint); } static struct KqueueRegisterOurselves @@ -78,8 +75,8 @@ static struct KqueueRegisterOurselves } } kQueueDoIt; -KqueueFDMultiplexer::KqueueFDMultiplexer() : - d_kevents(s_maxevents) +KqueueFDMultiplexer::KqueueFDMultiplexer(unsigned int maxEventsHint) : + d_kevents(maxEventsHint) { d_kqueuefd = kqueue(); if (d_kqueuefd < 0) { @@ -148,7 +145,7 @@ void KqueueFDMultiplexer::getAvailableFDs(std::vector& fds, int timeout) ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000000; - int ret = kevent(d_kqueuefd, 0, 0, d_kevents.data(), s_maxevents, &ts); + int ret = kevent(d_kqueuefd, 0, 0, d_kevents.data(), d_kevents.size(), &ts); if (ret < 0 && errno != EINTR) { throw FDMultiplexerException("kqueue returned error: " + stringerror()); @@ -177,7 +174,7 @@ int KqueueFDMultiplexer::run(struct timeval* now, int timeout) ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000000; - int ret = kevent(d_kqueuefd, 0, 0, d_kevents.data(), s_maxevents, &ts); + int ret = kevent(d_kqueuefd, 0, 0, d_kevents.data(), d_kevents.size(), &ts); gettimeofday(now, nullptr); // MANDATORY! if (ret < 0 && errno != EINTR) { diff --git a/pdns/mplexer.hh b/pdns/mplexer.hh index 9ff4ab18c1..bba581c31f 100644 --- a/pdns/mplexer.hh +++ b/pdns/mplexer.hh @@ -76,7 +76,11 @@ public: virtual ~FDMultiplexer() {} - static FDMultiplexer* getMultiplexerSilent(); + // The maximum number of events processed in a single run, not the maximum of watched descriptors + static constexpr unsigned int s_maxevents = 1024; + /* The maximum number of events processed in a single run will be capped to the + minimum value of maxEventsHint and s_maxevents, to reduce memory usage. */ + static FDMultiplexer* getMultiplexerSilent(unsigned int maxEventsHint = s_maxevents); /* tv will be updated to 'now' before run returns */ /* timeout is in ms */ @@ -206,7 +210,7 @@ public: return ret; } - typedef FDMultiplexer* getMultiplexer_t(); + typedef FDMultiplexer* getMultiplexer_t(unsigned int); typedef std::multimap FDMultiplexermap_t; static FDMultiplexermap_t& getMultiplexerMap() diff --git a/pdns/pollmplexer.cc b/pdns/pollmplexer.cc index 05ab28bf88..70a660ba89 100644 --- a/pdns/pollmplexer.cc +++ b/pdns/pollmplexer.cc @@ -9,12 +9,12 @@ #include "misc.hh" #include "namespaces.hh" -FDMultiplexer* FDMultiplexer::getMultiplexerSilent() +FDMultiplexer* FDMultiplexer::getMultiplexerSilent(unsigned int maxEventsHint) { FDMultiplexer* ret = nullptr; for (const auto& i : FDMultiplexer::getMultiplexerMap()) { try { - ret = i.second(); + ret = i.second(std::min(maxEventsHint, FDMultiplexer::s_maxevents)); return ret; } catch (const FDMultiplexerException& fe) { @@ -28,7 +28,7 @@ FDMultiplexer* FDMultiplexer::getMultiplexerSilent() class PollFDMultiplexer : public FDMultiplexer { public: - PollFDMultiplexer() + PollFDMultiplexer(unsigned int maxEventsHint) {} ~PollFDMultiplexer() { @@ -50,9 +50,9 @@ private: vector preparePollFD() const; }; -static FDMultiplexer* make() +static FDMultiplexer* make(unsigned int maxEventsHint) { - return new PollFDMultiplexer(); + return new PollFDMultiplexer(maxEventsHint); } static struct RegisterOurselves diff --git a/pdns/portsmplexer.cc b/pdns/portsmplexer.cc index f5e151043c..61333ef434 100644 --- a/pdns/portsmplexer.cc +++ b/pdns/portsmplexer.cc @@ -17,7 +17,7 @@ class PortsFDMultiplexer : public FDMultiplexer { public: - PortsFDMultiplexer(); + PortsFDMultiplexer(unsigned int maxEventsHint); ~PortsFDMultiplexer() { close(d_portfd); @@ -37,10 +37,9 @@ public: private: int d_portfd; std::vector d_pevents; - static int s_maxevents; // not a hard maximum }; -static FDMultiplexer* makePorts() +static FDMultiplexer* makePorts(unsigned int) { return new PortsFDMultiplexer(); } @@ -53,10 +52,8 @@ static struct PortsRegisterOurselves } } doItPorts; -int PortsFDMultiplexer::s_maxevents = 1024; - -PortsFDMultiplexer::PortsFDMultiplexer() : - d_pevents(s_maxevents) +PortsFDMultiplexer::PortsFDMultiplexer(unsigned int maxEventsHint) : + d_pevents(maxEventsHint) { d_portfd = port_create(); // not hard max if (d_portfd < 0) { @@ -97,7 +94,7 @@ void PortsFDMultiplexer::getAvailableFDs(std::vector& fds, int timeout) timeoutspec.tv_sec = timeout / 1000; timeoutspec.tv_nsec = (timeout % 1000) * 1000000; unsigned int numevents = 1; - int ret = port_getn(d_portfd, d_pevents.data(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeoutspec); + int ret = port_getn(d_portfd, d_pevents.data(), min(PORT_MAX_LIST, d_pevents.size()), &numevents, &timeoutspec); /* port_getn has an unusual API - (ret == -1, errno == ETIME) can mean partial success; you must check (*numevents) in this case @@ -158,7 +155,7 @@ int PortsFDMultiplexer::run(struct timeval* now, int timeout) timeoutspec.tv_sec = timeout / 1000; timeoutspec.tv_nsec = (timeout % 1000) * 1000000; unsigned int numevents = 1; - int ret = port_getn(d_portfd, d_pevents.data(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeoutspec); + int ret = port_getn(d_portfd, d_pevents.data(), min(PORT_MAX_LIST, d_pevents.size()), &numevents, &timeoutspec); /* port_getn has an unusual API - (ret == -1, errno == ETIME) can mean partial success; you must check (*numevents) in this case diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc index aed5c66b7d..ba6c1a48c7 100644 --- a/pdns/recursordist/rec-main.cc +++ b/pdns/recursordist/rec-main.cc @@ -340,7 +340,7 @@ static FDMultiplexer* getMultiplexer() FDMultiplexer* ret; for (const auto& i : FDMultiplexer::getMultiplexerMap()) { try { - ret = i.second(); + ret = i.second(FDMultiplexer::s_maxevents); return ret; } catch (FDMultiplexerException& fe) { diff --git a/pdns/test-mplexer.cc b/pdns/test-mplexer.cc index 7fe483d4bd..327eb39d22 100644 --- a/pdns/test-mplexer.cc +++ b/pdns/test-mplexer.cc @@ -24,7 +24,7 @@ BOOST_AUTO_TEST_CASE(test_getMultiplexerSilent) BOOST_AUTO_TEST_CASE(test_MPlexer) { for (const auto& entry : FDMultiplexer::getMultiplexerMap()) { - auto mplexer = std::unique_ptr(entry.second()); + auto mplexer = std::unique_ptr(entry.second(FDMultiplexer::s_maxevents)); BOOST_REQUIRE(mplexer != nullptr); //cerr<<"Testing multiplexer "<getName()<(entry.second()); + auto mplexer = std::unique_ptr(entry.second(FDMultiplexer::s_maxevents)); BOOST_REQUIRE(mplexer != nullptr); //cerr<<"Testing multiplexer "<getName()<<" for read AND write"<