From 24852b52f4f4087fd68cc63bc75d590833f5b8ac Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 24 Nov 2014 20:05:19 +0100 Subject: [PATCH] deps: reduce cpu profiler overhead * Block SIGPROF when in the epoll_pwait() system call so the event loop doesn't keep waking up on signal delivery. The clock_gettime() system call that libuv does after EINTR is very expensive on virtualized systems. * Replace sched_yield() with nanosleep() in V8's tick event processor thread. The former only yields the CPU when there is another process scheduled on the same CPU. * Fix a bug in the epoll_pwait() system call wrapper in libuv, see libuv/libuv#4. Refs strongloop/strong-agent#3 and strongloop-internal/scrum-cs#37. --- deps/uv/src/unix/linux-core.c | 26 +++++++++----------------- deps/uv/src/unix/linux-syscalls.c | 3 ++- deps/v8/src/platform-linux.cc | 4 +++- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 4846bd3fc71f..dd90cf0b0c3e 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -130,6 +130,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct uv__epoll_event e; ngx_queue_t* q; uv__io_t* w; + sigset_t set; uint64_t base; uint64_t diff; int nevents; @@ -138,7 +139,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int fd; int op; int i; - static int no_epoll_wait; if (loop->nfds == 0) { assert(ngx_queue_empty(&loop->watcher_queue)); @@ -184,23 +184,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ + sigemptyset(&set); + sigaddset(&set, SIGPROF); + for (;;) { - if (!no_epoll_wait) { - nfds = uv__epoll_wait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout); - if (nfds == -1 && errno == ENOSYS) { - no_epoll_wait = 1; - continue; - } - } else { - nfds = uv__epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - NULL); - } + nfds = uv__epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + &set); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index 06cc5943cf48..ee90b847c145 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -21,6 +21,7 @@ #include "linux-syscalls.h" #include +#include #include #include #include @@ -298,7 +299,7 @@ int uv__epoll_pwait(int epfd, nevents, timeout, sigmask, - sizeof(*sigmask)); + _NSIG / sizeof(long)); #else return errno = ENOSYS, -1; #endif diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index beb2ccee297f..cc9115d14b21 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -37,6 +37,7 @@ #include #include #include +#include // Ubuntu Dapper requires memory pages to be marked as // executable. Otherwise, OS raises an exception when executing code @@ -813,7 +814,8 @@ void Thread::SetThreadLocal(LocalStorageKey key, void* value) { void Thread::YieldCPU() { - sched_yield(); + const timespec delay = { 0, 1 }; + nanosleep(&delay, NULL); }