Commit 0df38a9b authored by Jason Madden's avatar Jason Madden

Make the libuv run QUEUE part of the loop.

Benchmarking (link in the email) showed that malloc/free had substantial and widely varying overhead.

I didn't really see much of a difference in the gevent benchmarks, but I didn't run them all. However, if any patch gets upstreamed, it will probably be something like this.

The link referenced in the email contains the discussion on the libuv mailing list.
parent d5942f40
================================
Managing Embedded Dependencies
================================
- Modify the c-ares Makefile.in[c] to empty out the MANPAGES variables
so that we don't have to ship those in the sdist.
XXX: We need a patch for that.
Updating libuv
==============
- Apply the gevent-libuv.patch to updates of libuv.
[deps] $ patch -p0 < gevent-libuv.patch
- Clean up the libuv tree:
- rm -rf libuv/.github
- rm -rf libuv/docs
- rm -rf libuv/samples
- rm -rf libuv/test
- rm -rf libuv/tools
- Create new patches by downloading the source tarball:
[deps] $ tar -xf libuv-v1.20.1.tar.gz
[deps] $ diff -r -u libuv-v1.20.1/ libuv > gevent-libuv.patch
diff --git a/deps/libuv/src/unix/loop-watcher.c b/deps/libuv/src/unix/loop-watcher.c
index 340bb0df..ff92c8e3 100644
--- a/deps/libuv/src/unix/loop-watcher.c
+++ b/deps/libuv/src/unix/loop-watcher.c
@@ -22,6 +22,17 @@
diff -r -u libuv-v1.20.1/include/uv-unix.h libuv/include/uv-unix.h
--- libuv-v1.20.1/include/uv-unix.h 2018-04-18 08:18:43.000000000 -0500
+++ libuv/include/uv-unix.h 2018-04-20 12:16:19.000000000 -0500
@@ -207,8 +207,11 @@
uv_handle_t* closing_handles; \
void* process_handles[2]; \
void* prepare_handles[2]; \
+ void* prepare_handles_queue[2]; \
void* check_handles[2]; \
+ void* check_handles_queue[2]; \
void* idle_handles[2]; \
+ void* idle_handles_queue[2]; \
void* async_handles[2]; \
void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \
uv__io_t async_io_watcher; \
diff -r -u libuv-v1.20.1/src/unix/loop-watcher.c libuv/src/unix/loop-watcher.c
--- libuv-v1.20.1/src/unix/loop-watcher.c 2018-04-18 08:18:43.000000000 -0500
+++ libuv/src/unix/loop-watcher.c 2018-04-20 13:59:36.000000000 -0500
@@ -22,6 +22,20 @@
#include "uv.h"
#include "internal.h"
+/*
+ * gevent: Fix for https://github.com/gevent/gevent/issues/1126
+ *
+ * Using a stack-based queue variable in uv__run_* badly breaks
+ * for certain stack manipulations when greenlets switch.
+ * Windows keeps the stack in the loop. In ordor to minimize changes,
+ * we move the stack to the heap by changing just this file. We can't
+ * use global static variables because of multiple threads.
+ * Using a stack-based queue variable in uv__run_* badly breaks for
+ * certain stack manipulations when greenlets switch. Windows keeps
+ * the stack in the loop. We originally used malloc/free in uv__run_
+ * to avoid changing any files but this one, but that benchmarked
+ * fairly slow and widely variable across processes
+ * (https://groups.google.com/d/msg/libuv/8BxOk40Dii4/Ke1yotOQBwAJ) so
+ * we moved them to the loop. We can't use global static variables
+ * because of multiple threads.
+ */
+#include <stdlib.h>
+
#define UV_LOOP_WATCHER_DEFINE(name, type) \
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
@@ -47,16 +58,17 @@
@@ -47,10 +61,10 @@
\
void uv__run_##name(uv_loop_t* loop) { \
uv_##name##_t* h; \
- QUEUE queue; \
+ QUEUE* queue = malloc(sizeof(QUEUE)); \
+ QUEUE* queue = &loop->name##_handles_queue; \
QUEUE* q; \
- QUEUE_MOVE(&loop->name##_handles, &queue); \
- while (!QUEUE_EMPTY(&queue)) { \
......@@ -34,10 +51,3 @@ index 340bb0df..ff92c8e3 100644
q = QUEUE_HEAD(&queue); \
h = QUEUE_DATA(q, uv_##name##_t, queue); \
QUEUE_REMOVE(q); \
QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
h->name##_cb(h); \
} \
+ free(queue); \
} \
\
void uv__##name##_close(uv_##name##_t* handle) { \
......@@ -207,8 +207,11 @@ typedef struct {
uv_handle_t* closing_handles; \
void* process_handles[2]; \
void* prepare_handles[2]; \
void* prepare_handles_queue[2]; \
void* check_handles[2]; \
void* check_handles_queue[2]; \
void* idle_handles[2]; \
void* idle_handles_queue[2]; \
void* async_handles[2]; \
void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \
uv__io_t async_io_watcher; \
......
......@@ -25,11 +25,14 @@
/*
* gevent: Fix for https://github.com/gevent/gevent/issues/1126
*
* Using a stack-based queue variable in uv__run_* badly breaks
* for certain stack manipulations when greenlets switch.
* Windows keeps the stack in the loop. In ordor to minimize changes,
* we move the stack to the heap by changing just this file. We can't
* use global static variables because of multiple threads.
* Using a stack-based queue variable in uv__run_* badly breaks for
* certain stack manipulations when greenlets switch. Windows keeps
* the stack in the loop. We originally used malloc/free in uv__run_
* to avoid changing any files but this one, but that benchmarked
* fairly slow and widely variable across processes
* (https://groups.google.com/d/msg/libuv/8BxOk40Dii4/Ke1yotOQBwAJ) so
* we moved them to the loop. We can't use global static variables
* because of multiple threads.
*/
#include <stdlib.h>
......@@ -58,7 +61,7 @@
\
void uv__run_##name(uv_loop_t* loop) { \
uv_##name##_t* h; \
QUEUE* queue = malloc(sizeof(QUEUE)); \
QUEUE* queue = &loop->name##_handles_queue; \
QUEUE* q; \
QUEUE_MOVE(&loop->name##_handles, queue); \
while (!QUEUE_EMPTY(queue)) { \
......@@ -68,7 +71,6 @@
QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
h->name##_cb(h); \
} \
free(queue); \
} \
\
void uv__##name##_close(uv_##name##_t* handle) { \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment