mirror of
https://github.com/matrix-construct/construct
synced 2024-11-29 02:02:38 +01:00
construct: Add boost::asio main event epoll_wait(2) optimization.
This commit is contained in:
parent
956ea6edb6
commit
7df5592ebe
2 changed files with 86 additions and 0 deletions
|
@ -30,6 +30,7 @@ AM_LDFLAGS = \
|
|||
-Wl,--dynamic-list-cpp-typeinfo \
|
||||
-Wl,--rosegment \
|
||||
-Wl,-z,noexecstack \
|
||||
-Wl,--wrap=epoll_wait \
|
||||
-L$(top_srcdir)/ircd \
|
||||
-L$(top_srcdir)/modules \
|
||||
$(PLATFORM_LDFLAGS) \
|
||||
|
|
|
@ -597,3 +597,88 @@ applyargs()
|
|||
if(quietmode)
|
||||
ircd::log::console_disable();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Unfortunate but worthwhile hack hook which allows us to optimize the
|
||||
// behavior of the boost::asio event loop by executing more queued tasks
|
||||
// before dropping to epoll_wait(2). This reduces the number of syscalls to
|
||||
// epoll_wait(2), which tend to occur at the start of every epoch except in a
|
||||
// minority of cases. These syscalls produced nothing 99% of the time.
|
||||
//
|
||||
// boost::asio tends to call epoll_wait(2) with timeout=0 (non-blocking) when
|
||||
// it has more work queued that it will execute. If there's nothing queued it
|
||||
// will set a timeout. We don't need to collect epoll events so aggressively,
|
||||
// Instead, we want to exhaust all work in userspace first, and then collect
|
||||
// events from the kernel. We lose some responsiveness with asio::signal_set
|
||||
// but gain overall performance in a post-meltdown/post-spectre virtualized
|
||||
// reality.
|
||||
//
|
||||
#if defined(BOOST_ASIO_HAS_EPOLL)
|
||||
|
||||
extern "C" int
|
||||
__real_epoll_wait(int __epfd, struct epoll_event *__events, int __maxevents, int __timeout);
|
||||
|
||||
extern "C" int
|
||||
__wrap_epoll_wait(int __epfd,
|
||||
struct epoll_event *const __events,
|
||||
int __maxevents,
|
||||
int __timeout)
|
||||
{
|
||||
static const uint64_t freq {12};
|
||||
static uint64_t calls, peeks, skips, results, stall[4];
|
||||
|
||||
const bool peek
|
||||
{
|
||||
__timeout == 0
|
||||
};
|
||||
|
||||
const bool tick
|
||||
{
|
||||
peeks % freq == 0
|
||||
};
|
||||
|
||||
const bool skip
|
||||
{
|
||||
peek && !tick
|
||||
};
|
||||
|
||||
const auto ret
|
||||
{
|
||||
!skip?
|
||||
__real_epoll_wait(__epfd, __events, __maxevents, __timeout): 0
|
||||
};
|
||||
|
||||
calls += 1;
|
||||
peeks += peek;
|
||||
skips += skip;
|
||||
results += ret > 0? ret: 0;
|
||||
stall[0] += ret >= 12;
|
||||
stall[1] += ret >= 24;
|
||||
stall[2] += ret >= 48;
|
||||
stall[3] += ret >= 96;
|
||||
|
||||
if constexpr(ircd::ios::profile::logging)
|
||||
if(!skip)
|
||||
ircd::log::logf
|
||||
{
|
||||
ircd::ios::log, ircd::log::DEBUG,
|
||||
"EPOLL * timeout:%d results:%lu calls:%lu skips:%lu peeks:%lu stall[%6lu][%6lu][%6lu][%6lu] = %d",
|
||||
__timeout,
|
||||
results,
|
||||
calls,
|
||||
skips,
|
||||
peeks,
|
||||
stall[0],
|
||||
stall[1],
|
||||
stall[2],
|
||||
stall[3],
|
||||
ret,
|
||||
};
|
||||
|
||||
assert(!skip || ret == 0);
|
||||
assert(ret <= 128);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue