remove unneeded io_getevents syscall.

Vadim Fedorenko vadimjunk at gmail.com
Sun Jan 6 21:40:28 UTC 2019


# HG changeset patch
# User Vadim Fedorenko <vadimjunk at gmail.com>
# Date 1546810494 0
#      Sun Jan 06 21:34:54 2019 +0000
# Node ID 3e538f6b8267d36f97b7dd67714c6ba0fba5e5bc
# Parent  6d15e452fa2eaf19408e24a0d0fcc3a31344a289
remove unneeded io_getevents syscall.

This work is based on cloudflare's work on optimization Linux AIO.
https://blog.cloudflare.com/io_submit-the-epoll-alternative-youve-never-heard-about/
The code is compilation of libaio library, it eliminates unnecessary
context-switch on getting new AIO events, doing all possible work in
userspace.

diff -r 6d15e452fa2e -r 3e538f6b8267 src/event/modules/ngx_epoll_module.c
--- a/src/event/modules/ngx_epoll_module.c    Tue Dec 25 17:53:03 2018 +0300
+++ b/src/event/modules/ngx_epoll_module.c    Sun Jan 06 21:34:54 2019 +0000
@@ -100,6 +100,35 @@
     ngx_uint_t  aio_requests;
 } ngx_epoll_conf_t;

+#if (NGX_HAVE_FILE_AIO)
+
+/* Stolen from kernel arch/x86_64.h */
+#ifdef __x86_64__
+#define read_barrier() __asm__ __volatile__("lfence" ::: "memory")
+#else
+#ifdef __i386__
+#define read_barrier() __asm__ __volatile__("" : : : "memory")
+#else
+#define read_barrier() __sync_synchronize()
+#endif
+#endif
+
+/* Stolen from kernel fs/aio.c */
+#define AIO_RING_MAGIC                  0xa10a10a1
+struct aio_ring {
+    unsigned        id;     /* kernel internal index number */
+    unsigned        nr;     /* number of io_events */
+    unsigned        head;
+    unsigned        tail;
+    unsigned        magic;
+    unsigned        compat_features;
+    unsigned        incompat_features;
+    unsigned        header_length;  /* size of aio_ring */
+    struct io_event events[0];
+};
+
+#endif
+

 static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
 #if (NGX_HAVE_EVENTFD)
@@ -241,6 +270,39 @@
 io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events,
     struct timespec *tmo)
 {
+    /* Code based on cloudflare-blog */
+    ngx_int_t i = 0;
+
+    struct aio_ring *ring = (struct aio_ring *)ctx;
+    if (ring == NULL || ring->magic != AIO_RING_MAGIC) {
+        goto do_syscall;
+    }
+
+    while (i < nr) {
+        unsigned head = ring->head;
+        if (head == ring->tail) {
+            /* There are no more completions */
+            break;
+        } else {
+            /* There is another completion to reap */
+            events[i] = ring->events[head];
+            read_barrier();
+            ring->head = (head + 1) % ring->nr;
+            i++;
+        }
+    }
+
+    if (i == 0 && tmo != NULL && tmo->tv_sec == 0 &&
+        tmo->tv_nsec == 0) {
+        /* Requested non blocking operation. */
+        return 0;
+    }
+
+    if (i && i >= min_nr) {
+        return i;
+    }
+
+do_syscall:
     return syscall(SYS_io_getevents, ctx, min_nr, nr, events, tmo);
 }


More information about the nginx-devel mailing list