From 4fe852430f8f78265be1bbc01e897f0d889f6d7e Mon Sep 17 00:00:00 2001 From: Konstantin Osipov <kostja@tarantool.org> Date: Fri, 20 Mar 2015 17:05:15 +0300 Subject: [PATCH] fiber scheduling: schedule ready fibers more aggressively If a fiber becomes ready on a user-defined event, schedule it in the same event loop, not in the next loop, to save one epoll_wait() invocation in cases when something is added to a fiber channel, and there is a fiber ready for execution waiting on the channel. Add a micro-bench to the unit test suite. --- src/fiber.cc | 18 ++++++------- test/unit/CMakeLists.txt | 3 +++ test/unit/ipc.cc | 55 ++++++++++++++++++++++++++++++++++++++++ test/unit/ipc.result | 3 +++ 4 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 test/unit/ipc.cc create mode 100644 test/unit/ipc.result diff --git a/src/fiber.cc b/src/fiber.cc index ff02fb3132..111aaca7da 100644 --- a/src/fiber.cc +++ b/src/fiber.cc @@ -105,12 +105,12 @@ fiber_wakeup(struct fiber *f) if (rlist_empty(&cord->ready)) { /* * ev_feed_event() is possibly faster, - * but custom event gets scheduled in the + * but EV_CUSTOM event gets scheduled in the * same event loop iteration, which can - * produce unfair scheduling (see the case of + * produce unfair scheduling, (see the case of * fiber_sleep(0)) */ - ev_async_send(cord->loop, &cord->wakeup_event); + ev_feed_event(cord->loop, &cord->wakeup_event, EV_CUSTOM); } rlist_move_tail_entry(&cord->ready, f, state); } @@ -293,13 +293,11 @@ fiber_yield_timeout(ev_tstamp delay) void fiber_sleep(ev_tstamp delay) { - if (delay == 0) { - /* Faster than starting and stopping a timer. */ - fiber_wakeup(fiber()); - fiber_yield(); - } else { - fiber_yield_timeout(delay); - } + /* + * We don't use fiber_wakeup() here to ensure there is + * no infinite wakeup loop in case of fiber_sleep(0). + */ + fiber_yield_timeout(delay); fiber_testcancel(); } diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 1b8d8c0088..4833461371 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -65,6 +65,9 @@ target_link_libraries(fiber.test core) add_executable(fiber_stress.test fiber_stress.cc) target_link_libraries(fiber_stress.test core) +add_executable(ipc.test ipc.cc ${CMAKE_SOURCE_DIR}/src/ipc.cc) +target_link_libraries(ipc.test core) + add_executable(coio.test coio.cc unit.c ${CMAKE_SOURCE_DIR}/src/sio.cc ${CMAKE_SOURCE_DIR}/src/evio.cc diff --git a/test/unit/ipc.cc b/test/unit/ipc.cc new file mode 100644 index 0000000000..c5812bbf90 --- /dev/null +++ b/test/unit/ipc.cc @@ -0,0 +1,55 @@ +#include "memory.h" +#include "fiber.h" +#include "ipc.h" +#include "unit.h" + +enum { + ITERATIONS = 100000, +}; + +void +push_f(va_list ap) +{ + struct ipc_channel *channel = va_arg(ap, struct ipc_channel *); + + for (int i = 0; i < ITERATIONS; i++) + ipc_channel_put(channel, NULL); +} + +void +pop_f(va_list ap) +{ + struct ipc_channel *channel = va_arg(ap, struct ipc_channel *); + + for (int i = 0; i < ITERATIONS; i++) + (void) ipc_channel_get(channel); +} + +void main_f(va_list ap) +{ + header(); + struct fiber *push = fiber_new("push_f", push_f); + fiber_set_joinable(push, true); + struct fiber *pop = fiber_new("pop_f", pop_f); + fiber_set_joinable(pop, true); + struct ipc_channel *channel = ipc_channel_new(1); + fiber_start(push, channel); + fiber_start(pop, channel); + fiber_join(push); + fiber_join(pop); + ipc_channel_delete(channel); + ev_break(loop(), EVBREAK_ALL); + footer(); +} + +int main() +{ + memory_init(); + fiber_init(); + struct fiber *main= fiber_new("main", main_f); + fiber_wakeup(main); + ev_run(loop(), 0); + fiber_free(); + memory_free(); + return 0; +} diff --git a/test/unit/ipc.result b/test/unit/ipc.result new file mode 100644 index 0000000000..f3398fb9c7 --- /dev/null +++ b/test/unit/ipc.result @@ -0,0 +1,3 @@ + *** main_f *** + *** main_f: done *** + \ No newline at end of file -- GitLab