From 65fa1d9bf339c2f661f6ff7973a6716ebc433265 Mon Sep 17 00:00:00 2001 From: cohcho Date: Mon, 12 Oct 2020 04:09:09 +0000 Subject: [PATCH] uv: fix performance issue unix implementation of uv_async_t has been wasting cpu cycles for nothing since 1.29.0 release implement efficient callback scheduling for linux --- src/base/base.cmake | 3 ++ src/base/io/Async.cpp | 78 +++++++++++++++++++++++++++++++++++++++++ src/base/io/Async.h | 27 ++++++++++++++ src/crypto/rx/RxQueue.h | 1 + src/net/JobResults.cpp | 1 + 5 files changed, 110 insertions(+) create mode 100644 src/base/io/Async.cpp create mode 100644 src/base/io/Async.h diff --git a/src/base/base.cmake b/src/base/base.cmake index da53d5ea8..0574d617e 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -130,6 +130,9 @@ else() src/base/io/json/Json_unix.cpp src/base/kernel/Platform_unix.cpp ) + list(APPEND SOURCES_BASE + src/base/io/Async.cpp + ) endif() diff --git a/src/base/io/Async.cpp b/src/base/io/Async.cpp new file mode 100644 index 000000000..9ac8b02a2 --- /dev/null +++ b/src/base/io/Async.cpp @@ -0,0 +1,78 @@ +#include "base/io/Async.h" + + +#if defined(XMRIG_UV_PERFORMANCE_BUG) +#include +#include +#include +#include + + +namespace xmrig { + + +uv_async_t::~uv_async_t() +{ + close(m_fd); +} + + +static void on_schedule(uv_poll_t *handle, int status, int events) +{ + static uint64_t val; + uv_async_t *async = reinterpret_cast(handle); + for (;;) { + int r = read(async->m_fd, &val, sizeof(val)); + + if (r == sizeof(val)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + if (async->m_cb) { + (*async->m_cb)(async); + } +} + + +int uv_async_init(uv_loop_t *loop, uv_async_t *async, uv_async_cb cb) +{ + int fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (fd < 0) { + return uv_translate_sys_error(errno); + } + uv_poll_init(loop, (uv_poll_t *)async, fd); + uv_poll_start((uv_poll_t *)async, POLLIN, on_schedule); + async->m_cb = cb; + async->m_fd = fd; + return 0; +} + + +int uv_async_send(uv_async_t *async) +{ + static const uint64_t val = 1; + int r; + do { + r = write(async->m_fd, &val, sizeof(val)); + } + while (r == -1 && errno == EINTR); + if (r == sizeof(val) || (r == 1 && (errno == EAGAIN || errno == EWOULDBLOCK))) { + return 0; + } + abort(); +} + + + +} // namespace xmrig +#endif diff --git a/src/base/io/Async.h b/src/base/io/Async.h new file mode 100644 index 000000000..4af45f3f1 --- /dev/null +++ b/src/base/io/Async.h @@ -0,0 +1,27 @@ +#pragma once + +#include + + +// since 2019.05.16, Version 1.29.0 (Stable) +#if (UV_VERSION_MAJOR >= 1) && (UV_VERSION_MINOR >= 29) && defined(__linux__) +#define XMRIG_UV_PERFORMANCE_BUG +namespace xmrig { + + +struct uv_async_t: uv_poll_t +{ + typedef void (*uv_async_cb)(uv_async_t* handle); + ~uv_async_t(); + int m_fd = -1; + uv_async_cb m_cb = nullptr; +}; + + +using uv_async_cb = uv_async_t::uv_async_cb; +extern int uv_async_init(uv_loop_t *loop, uv_async_t *async, uv_async_cb cb); +extern int uv_async_send(uv_async_t *async); + + +} // namespace xmrig +#endif diff --git a/src/crypto/rx/RxQueue.h b/src/crypto/rx/RxQueue.h index fca4a12fc..bee2bbd2a 100644 --- a/src/crypto/rx/RxQueue.h +++ b/src/crypto/rx/RxQueue.h @@ -28,6 +28,7 @@ #define XMRIG_RX_QUEUE_H +#include "base/io/Async.h" #include "base/tools/Object.h" #include "crypto/common/HugePagesInfo.h" #include "crypto/rx/RxConfig.h" diff --git a/src/net/JobResults.cpp b/src/net/JobResults.cpp index 06118657f..c54b85d34 100644 --- a/src/net/JobResults.cpp +++ b/src/net/JobResults.cpp @@ -24,6 +24,7 @@ #include "net/JobResults.h" +#include "base/io/Async.h" #include "base/io/log/Log.h" #include "base/tools/Handle.h" #include "base/tools/Object.h"