linux: use eventfds for async handles
Use eventfds to drive async handles, fall back to regular pipes on older kernels (pre-2.6.22). Gives a nice boost on the async handle benchmarks. Before: 12,516,113 async events in 5.0 seconds (2,503,222/s, 1,048,576 unique async1: 11.95 sec (83,701/sec) async2: 11.65 sec (85,862/sec) async4: 5.20 sec (192,154/sec) async8: 9.97 sec (100,315/sec) async_pummel_1: 1,000,000 callbacks in 2.56 seconds (389,919/sec) async_pummel_2: 1,000,000 callbacks in 2.65 seconds (377,205/sec) async_pummel_4: 1,000,000 callbacks in 2.18 seconds (457,704/sec) async_pummel_8: 1,000,000 callbacks in 4.19 seconds (238,632/sec) After: 16,168,081 async events in 5.0 seconds (3,233,616/s, 1,048,576 unique async1: 11.08 sec (90,213/sec) async2: 10.17 sec (98,297/sec) async4: 4.81 sec (207,789/sec) async8: 8.98 sec (111,419/sec) async_pummel_1: 1,000,000 callbacks in 1.16 seconds (863,296/sec) async_pummel_2: 1,000,000 callbacks in 1.45 seconds (691,459/sec) async_pummel_4: 1,000,000 callbacks in 0.66 seconds (1,514,770/sec) async_pummel_8: 1,000,000 callbacks in 1.42 seconds (704,549/sec) That's a speedup from anywhere between 10% to 330%.
This commit is contained in:
parent
92151658eb
commit
b04fc33ef7
@ -28,12 +28,14 @@
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void uv__async_event(uv_loop_t* loop,
|
||||
struct uv__async* w,
|
||||
unsigned int nevents);
|
||||
static int uv__async_make_pending(int* pending);
|
||||
static int uv__async_eventfd(void);
|
||||
|
||||
|
||||
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
||||
@ -140,18 +142,45 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
}
|
||||
|
||||
wa = container_of(w, struct uv__async, io_watcher);
|
||||
|
||||
#if defined(__linux__)
|
||||
if (wa->wfd == -1) {
|
||||
uint64_t val;
|
||||
assert(n == sizeof(val));
|
||||
memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */
|
||||
wa->cb(loop, wa, val);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
wa->cb(loop, wa, n);
|
||||
}
|
||||
|
||||
|
||||
void uv__async_send(struct uv__async* wa) {
|
||||
const void* buf;
|
||||
ssize_t len;
|
||||
int fd;
|
||||
int r;
|
||||
|
||||
buf = "";
|
||||
len = 1;
|
||||
fd = wa->wfd;
|
||||
|
||||
#if defined(__linux__)
|
||||
if (fd == -1) {
|
||||
static const uint64_t val = 1;
|
||||
buf = &val;
|
||||
len = sizeof(val);
|
||||
fd = wa->io_watcher.fd; /* eventfd */
|
||||
}
|
||||
#endif
|
||||
|
||||
do
|
||||
r = write(wa->wfd, "", 1);
|
||||
r = write(fd, buf, len);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == 1)
|
||||
if (r == len)
|
||||
return;
|
||||
|
||||
if (r == -1)
|
||||
@ -170,11 +199,19 @@ void uv__async_init(struct uv__async* wa) {
|
||||
|
||||
int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
|
||||
int pipefd[2];
|
||||
int fd;
|
||||
|
||||
if (wa->io_watcher.fd != -1)
|
||||
return 0;
|
||||
|
||||
if (uv__make_pipe(pipefd, UV__F_NONBLOCK))
|
||||
fd = uv__async_eventfd();
|
||||
if (fd >= 0) {
|
||||
pipefd[0] = fd;
|
||||
pipefd[1] = -1;
|
||||
}
|
||||
else if (fd != -ENOSYS)
|
||||
return -1;
|
||||
else if (uv__make_pipe(pipefd, UV__F_NONBLOCK))
|
||||
return -1;
|
||||
|
||||
uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]);
|
||||
@ -192,8 +229,53 @@ void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) {
|
||||
|
||||
uv__io_stop(loop, &wa->io_watcher, UV__POLLIN);
|
||||
close(wa->io_watcher.fd);
|
||||
close(wa->wfd);
|
||||
|
||||
wa->io_watcher.fd = -1;
|
||||
wa->wfd = -1;
|
||||
|
||||
if (wa->wfd != -1) {
|
||||
close(wa->wfd);
|
||||
wa->wfd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__async_eventfd() {
|
||||
#if defined(__linux__)
|
||||
static int no_eventfd2;
|
||||
static int no_eventfd;
|
||||
int fd;
|
||||
|
||||
if (no_eventfd2)
|
||||
goto skip_eventfd2;
|
||||
|
||||
fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return -errno;
|
||||
|
||||
no_eventfd2 = 1;
|
||||
|
||||
skip_eventfd2:
|
||||
|
||||
if (no_eventfd)
|
||||
goto skip_eventfd;
|
||||
|
||||
fd = uv__eventfd(0);
|
||||
if (fd != -1) {
|
||||
uv__cloexec(fd, 1);
|
||||
uv__nonblock(fd, 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return -errno;
|
||||
|
||||
no_eventfd = 1;
|
||||
|
||||
skip_eventfd:
|
||||
|
||||
#endif
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user