From d9cb2dafa453eab52b0f70c7c8607db37f18dbd1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 2 Nov 2012 13:45:49 +0100 Subject: [PATCH 1/3] lib/tsocket: disable the syscall optimization for recvfrom/readv by default We only do the optimization on recvfrom/readv if the caller asked for it. This is needed because in most cases we preferr to flush send buffers before receiving incoming requests. Signed-off-by: Stefan Metzmacher --- lib/tsocket/tsocket.h | 42 ++++++++++++++++++++++++++ lib/tsocket/tsocket_bsd.c | 73 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 109 insertions(+), 6 deletions(-) diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h index 3aca536..98f864e 100644 --- a/lib/tsocket/tsocket.h +++ b/lib/tsocket/tsocket.h @@ -627,6 +627,27 @@ int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx, char *tsocket_address_unix_path(const struct tsocket_address *addr, TALLOC_CTX *mem_ctx); +/** + * @brief Request a syscall optimization for tdgram_recvfrom_send() + * + * This function is only used to reduce the amount of syscalls and + * optimize performance. You should only use this if you know + * what you're doing. + * + * The optimization is off by default. + * + * @param[in] dgram The tdgram_context of a bsd socket, if this + * not a bsd socket the function does nothing. + * + * @param[in] on The boolean value to turn the optimization on and off. + * + * @return The old boolean value. + * + * @see tdgram_recvfrom_send() + */ +bool tdgram_bsd_optimize_recvfrom(struct tdgram_context *dgram, + bool on); + #ifdef DOXYGEN /** * @brief Create a tdgram_context for a ipv4 or ipv6 UDP communication. @@ -689,6 +710,27 @@ int _tdgram_unix_socket(const struct tsocket_address *local, #endif /** + * @brief Request a syscall optimization for tstream_readv_send() + * + * This function is only used to reduce the amount of syscalls and + * optimize performance. You should only use this if you know + * what you're doing. + * + * The optimization is off by default. + * + * @param[in] stream The tstream_context of a bsd socket, if this + * not a bsd socket the function does nothing. + * + * @param[in] on The boolean value to turn the optimization on and off. + * + * @return The old boolean value. + * + * @see tstream_readv_send() + */ +bool tstream_bsd_optimize_readv(struct tstream_context *stream, + bool on); + +/** * @brief Connect async to a TCP endpoint and create a tstream_context for the * stream based communication. * diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c index 9e80065..58598d1 100644 --- a/lib/tsocket/tsocket_bsd.c +++ b/lib/tsocket/tsocket_bsd.c @@ -654,6 +654,7 @@ struct tdgram_bsd { void *event_ptr; struct tevent_fd *fde; + bool optimize_recvfrom; void *readable_private; void (*readable_handler)(void *private_data); @@ -661,6 +662,25 @@ struct tdgram_bsd { void (*writeable_handler)(void *private_data); }; +bool tdgram_bsd_optimize_recvfrom(struct tdgram_context *dgram, + bool on) +{ + struct tdgram_bsd *bsds = + talloc_get_type(_tdgram_context_data(dgram), + struct tdgram_bsd); + bool old; + + if (bsds == NULL) { + /* not a bsd socket */ + return false; + } + + old = bsds->optimize_recvfrom; + bsds->optimize_recvfrom = on; + + return old; +} + static void tdgram_bsd_fde_handler(struct tevent_context *ev, struct tevent_fd *fde, uint16_t flags, @@ -837,14 +857,25 @@ static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx, goto post; } + /* * this is a fast path, not waiting for the * socket to become explicit readable gains * about 10%-20% performance in benchmark tests. */ - tdgram_bsd_recvfrom_handler(req); - if (!tevent_req_is_in_progress(req)) { - goto post; + if (bsds->optimize_recvfrom) { + /* + * We only do the optimization on + * recvfrom if the caller asked for it. + * + * This is needed because in most cases + * we preferr to flush send buffers before + * receiving incoming requests. + */ + tdgram_bsd_recvfrom_handler(req); + if (!tevent_req_is_in_progress(req)) { + goto post; + } } ret = tdgram_bsd_set_readable_handler(bsds, ev, @@ -1400,6 +1431,7 @@ struct tstream_bsd { void *event_ptr; struct tevent_fd *fde; + bool optimize_readv; void *readable_private; void (*readable_handler)(void *private_data); @@ -1407,6 +1439,25 @@ struct tstream_bsd { void (*writeable_handler)(void *private_data); }; +bool tstream_bsd_optimize_readv(struct tstream_context *stream, + bool on) +{ + struct tstream_bsd *bsds = + talloc_get_type(_tstream_context_data(stream), + struct tstream_bsd); + bool old; + + if (bsds == NULL) { + /* not a bsd socket */ + return false; + } + + old = bsds->optimize_readv; + bsds->optimize_readv = on; + + return old; +} + static void tstream_bsd_fde_handler(struct tevent_context *ev, struct tevent_fd *fde, uint16_t flags, @@ -1619,9 +1670,19 @@ static struct tevent_req *tstream_bsd_readv_send(TALLOC_CTX *mem_ctx, * socket to become explicit readable gains * about 10%-20% performance in benchmark tests. */ - tstream_bsd_readv_handler(req); - if (!tevent_req_is_in_progress(req)) { - goto post; + if (bsds->optimize_readv) { + /* + * We only do the optimization on + * readv if the caller asked for it. + * + * This is needed because in most cases + * we preferr to flush send buffers before + * receiving incoming requests. + */ + tstream_bsd_readv_handler(req); + if (!tevent_req_is_in_progress(req)) { + goto post; + } } ret = tstream_bsd_set_readable_handler(bsds, ev, -- 1.7.0.4 From f23c206169e4e9a1ea2aec7f1e6d86564e4257c8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 2 Nov 2012 13:56:53 +0100 Subject: [PATCH 2/3] lib/tsocket: optimize syscalls in tstream_readv_pdu_send() Once we've got the first part of a pdu we try to optimize readv calls for the rest of the pdu. Signed-off-by: Stefan Metzmacher --- lib/tsocket/tsocket_helpers.c | 29 +++++++++++++++++++++++++++++ 1 files changed, 29 insertions(+), 0 deletions(-) diff --git a/lib/tsocket/tsocket_helpers.c b/lib/tsocket/tsocket_helpers.c index 3a41a3e..809830d 100644 --- a/lib/tsocket/tsocket_helpers.c +++ b/lib/tsocket/tsocket_helpers.c @@ -212,6 +212,20 @@ static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req) size_t to_read = 0; size_t i; struct tevent_req *subreq; + bool optimize = false; + bool save_optimize = false; + + if (state->count > 0) { + /* + * This is not the first time we asked for a vector, + * which means parts of the pdu already arrived. + * + * In this case it make sense to enable + * a syscall/performance optimization if the + * low level tstream implementation supports it. + */ + optimize = true; + } TALLOC_FREE(state->vector); state->count = 0; @@ -255,11 +269,26 @@ static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req) return; } + if (optimize) { + /* + * If the low level stream is a bsd socket + * we will get syscall optimization. + * + * If it is not a bsd socket + * tstream_bsd_optimize_readv() just returns. + */ + save_optimize = tstream_bsd_optimize_readv(state->caller.stream, + true); + } subreq = tstream_readv_send(state, state->caller.ev, state->caller.stream, state->vector, state->count); + if (optimize) { + tstream_bsd_optimize_readv(state->caller.stream, + save_optimize); + } if (tevent_req_nomem(subreq, req)) { return; } -- 1.7.0.4 From 0a01ecdf484a0c574b4dae40e7a028b2942a9fb1 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 5 Nov 2012 15:53:31 +0100 Subject: [PATCH 3/3] s3-aio_pthread: Optimize aio_pthread_handle_completion Read as much as we can --- source3/modules/vfs_aio_pthread.c | 58 ++++++++++++++++++++++++++----------- 1 files changed, 41 insertions(+), 17 deletions(-) diff --git a/source3/modules/vfs_aio_pthread.c b/source3/modules/vfs_aio_pthread.c index ceef822..6627811 100644 --- a/source3/modules/vfs_aio_pthread.c +++ b/source3/modules/vfs_aio_pthread.c @@ -74,6 +74,7 @@ static bool init_aio_threadpool(struct vfs_handle_struct *handle) struct fd_event *sock_event = NULL; int ret = 0; int num_threads; + int fd; if (pool) { return true; @@ -85,9 +86,14 @@ static bool init_aio_threadpool(struct vfs_handle_struct *handle) errno = ret; return false; } + + fd = pthreadpool_signal_fd(pool); + + set_blocking(fd, false); + sock_event = tevent_add_fd(server_event_context(), NULL, - pthreadpool_signal_fd(pool), + fd, TEVENT_FD_READ, aio_pthread_handle_completion, NULL); @@ -290,25 +296,43 @@ static void aio_pthread_handle_completion(struct event_context *event_ctx, return; } - ret = pthreadpool_finished_job(pool, &jobid); - if (ret) { - smb_panic("aio_pthread_handle_completion"); - return; - } + while (true) { + ret = pthreadpool_finished_job(pool, &jobid); - pd = find_private_data_by_jobid(jobid); - if (pd == NULL) { - DEBUG(1, ("aio_pthread_handle_completion cannot find jobid %d\n", - jobid)); - return; - } + if (ret == EINTR || ret == EAGAIN) { + return; + } +#ifdef EWOULDBLOCK + if (ret == EWOULDBLOCK) { + return; + } +#endif - aio_ex = (struct aio_extra *)pd->aiocb->aio_sigevent.sigev_value.sival_ptr; - smbd_aio_complete_aio_ex(aio_ex); + if (ret == ECANCELED) { + return; + } - DEBUG(10,("aio_pthread_handle_completion: jobid %d completed\n", - jobid )); - TALLOC_FREE(aio_ex); + if (ret) { + smb_panic("aio_pthread_handle_completion"); + return; + } + + pd = find_private_data_by_jobid(jobid); + if (pd == NULL) { + DEBUG(1, ("aio_pthread_handle_completion cannot find " + "jobid %d\n", jobid)); + return; + } + + aio_ex = (struct aio_extra *) + pd->aiocb->aio_sigevent.sigev_value.sival_ptr; + + smbd_aio_complete_aio_ex(aio_ex); + + DEBUG(10,("aio_pthread_handle_completion: jobid %d " + "completed\n", jobid )); + TALLOC_FREE(aio_ex); + } } /************************************************************************ -- 1.7.0.4