From: Vladimir Davydov via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Cc: tarantool-patches@dev.tarantool.org Subject: Re: [Tarantool-patches] [PATCH 15/20] net.box: rewrite request implementation in C Date: Wed, 4 Aug 2021 15:30:01 +0300 [thread overview] Message-ID: <20210804123001.3cwudybvkw6dds74@esperanza> (raw) In-Reply-To: <903f6291-bab5-985e-f922-042453e4d146@tarantool.org> On Mon, Aug 02, 2021 at 11:54:43PM +0200, Vladislav Shpilevoy wrote: > In an early version I saw on the branch you tried to keep the > discarded requests in the hash. It is not so anymore, correct? > Now discarded requests are GCed even their response didn't arrive > yet? (It should be so, but I decided to clarify just in case.) Both original version and the current version pushed to the branch remove discarded requests from the hash (both luaT_netbox_request_gc and luaT_netbox_request_discard call netbox_request_unregister, which removes the request from the hash table). > > +struct netbox_registry { > > + /* sync -> netbox_request */ > > 1. For out of function comments we usually use /**. This includes the > comments for structs and their members. Fixed here, there, and everywhere. > > +struct netbox_request { > > + /* > > + * Reference to the request result or LUA_NOREF if the response hasn't > > + * been received yet. If the response was decoded to a user-provided > > + * buffer, the result stores the length of the decoded data. > > 2. Do you mean result_ref stores the length? I can't find it in the code. > It always stores a real Lua ref from what I see. Yes, it always stores a Lua ref. In case the result is written to a user-provided buffer, it stores a reference to the result lenght. Updated the comment to clarify that. > > + */ > > + int result_ref; > > + /* > > + * Error if the request failed (ref incremented). NULL on success or if > > + * the response hasn't been received yet. > > + */ > > + struct error *error; > > + > > 3. Extra empty line. Removed. > > +static bool > > +netbox_request_is_ready(struct netbox_request *request) > > 4. The request can be made 'const'. Added. > > +static bool > > +netbox_request_wait(struct netbox_request *request, double *timeout) > > +{ > > + double ts = ev_monotonic_now(loop()); > > 5. fiber_clock() might be a little shorter (does the same). The same below. > Although it is not inline. Up to you. Also see a related comment below. We use ev_monotonic_now in more places in the code so I'm going to stick to it: ~/src/tarantool$ git grep fiber_clock src | grep -c -v -e '\.lua:' 19 ~/src/tarantool$ git grep ev_monotonic_now src | grep -c -v -e '\.lua:' 60 > > 6. Have you tried making these 1-5 line functions explicitly inline? > I remember with Mergen we saw some actual perf difference in SQL code > when did so. Although that time the functions were in the header vs in > a .c file. > > I see you used inline for some functions in this commit. Why not for > the ones like these? Marked all short, frequently called functions 'inline'. It didn't affect the test results though. > > +static int > > +luaT_netbox_request_wait_result(struct lua_State *L) > > +{ > > + struct netbox_request *request = luaT_check_netbox_request(L, 1); > > + double timeout = TIMEOUT_INFINITY; > > + if (!lua_isnoneornil(L, 2)) { > > + if (lua_type(L, 2) != LUA_TNUMBER || > > + (timeout = lua_tonumber(L, 2)) < 0) > > + luaL_error(L, "Usage: future:wait_result(timeout)"); > > + } > > + while (!netbox_request_is_ready(request)) { > > + if (!netbox_request_wait(request, &timeout)) { > > + luaL_testcancel(L); > > + diag_set(ClientError, ER_TIMEOUT); > > 7. In some places you use box_error_raise(), in others the > explicit diag_set(ClientError). Why? For instance: > > box_error_raise(ER_NO_CONNECTION, "%s", strerror(errno)); > box_error_raise(ER_NO_CONNECTION, "Peer closed"); > > In others the raise is justified because you do not know the > error code and its message at compile time there. In these 2 > I probably do not know something? box_error_raise() allows you to set an arbitrary error message while diag_set() uses error messages corresponding to error codes (src/box/errcode.h). E.g. for ER_NO_CONNECTION, it's always "Connection is not established". I use box_error_raise() here in order to avoid changing error messages which were reported by Lua code originally. > > +static int > > +luaT_netbox_request_pairs(struct lua_State *L) > > +{ > > + if (!lua_isnoneornil(L, 2)) { > > + if (lua_type(L, 2) != LUA_TNUMBER || lua_tonumber(L, 2) < 0) > > + luaL_error(L, "Usage: future:pairs(timeout)"); > > + } else { > > + if (lua_isnil(L, 2)) > > + lua_pop(L, 1); > > + lua_pushnumber(L, TIMEOUT_INFINITY); > > + } > > + lua_pushcclosure(L, luaT_netbox_request_iterator_next, 2); > > 8. Push of cfunctions, especially closures, on a regular basis might > be expensive. Could you please try to make it a non-closure function > and cache its reference like I showed in the proposal about request __gc? My test doesn't check performance of the request iterator so I need to come up with a new test first to check this hypothesis. I'll reply to this email with the results once they're ready. > > +static int > > +netbox_new_request(struct lua_State *L) > > +{ > > + struct netbox_request *request = lua_newuserdata(L, sizeof(*request)); > > 9. Does it help perf if the requests are allocated on mempool? I tried to allocate requests on mempool. To achieve that, we have to turn them into C data. It resulted in a performance degradation, see the parallel thread: https://lists.tarantool.org/pipermail/tarantool-patches/2021-July/025039.html The code is here (last two commits): https://github.com/tarantool/tarantool/tree/vdavydov/net-box-optimization-cdata-request Lua does a lot of malloc calls under the hood. Eliminating just this one newuserdata doesn't seem to make any difference. > > + netbox_request_create(request); > > 10. Below you override a lot of fields initialized in > netbox_request_create(). Do you really need this create(), can you > inline it without the unnecessary assignments? Right. Removed netbox_request_create. > > + luaL_getmetatable(L, netbox_request_typename); > > + lua_setmetatable(L, -2); > > + struct netbox_registry *registry = luaT_check_netbox_registry(L, 1); > > + request->sync = luaL_touint64(L, 2); > > + request->buffer = (struct ibuf *) lua_topointer(L, 3); > > + lua_pushvalue(L, 3); > > + request->buffer_ref = luaL_ref(L, LUA_REGISTRYINDEX); > > + request->skip_header = lua_toboolean(L, 4); > > + request->method = lua_tointeger(L, 5); > > + assert(request->method < netbox_method_MAX); > > + lua_pushvalue(L, 6); > > + request->on_push_ref = luaL_ref(L, LUA_REGISTRYINDEX); > > + lua_pushvalue(L, 7); > > + request->on_push_ctx_ref = luaL_ref(L, LUA_REGISTRYINDEX); > > + if (!lua_isnil(L, 8)) > > + request->format = lbox_check_tuple_format(L, 8); > > + else > > + request->format = tuple_format_runtime; > > + tuple_format_ref(request->format); > > + if (netbox_request_register(request, registry) != 0) > > + luaT_error(L); > > + return 1; > > +} > > diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua > > index 0ad6cac022f2..4bc66940ea2a 100644 > > --- a/src/box/lua/net_box.lua > > +++ b/src/box/lua/net_box.lua > > @@ -468,20 +304,8 @@ local function create_transport(host, port, user, password, callback, > > local id = next_request_id > > encode_method(method, send_buf, id, ...) > > next_request_id = next_id(id) > > - -- Request in most cases has maximum 10 members: > > - -- method, buffer, skip_header, id, cond, errno, response, > > - -- on_push, on_push_ctx and format. > > - local request = setmetatable(table_new(0, 10), request_mt) > > - request.method = method > > - request.buffer = buffer > > - request.skip_header = skip_header > > - request.id = id > > - request.cond = fiber.cond() > > - requests[id] = request > > - request.on_push = on_push > > - request.on_push_ctx = on_push_ctx > > - request.format = format > > - return request > > + return internal.new_request(requests, id, buffer, skip_header, method, > > + on_push, on_push_ctx, format) > > 11. You might want to try to cache internal.new_request globally, > use it without '.' operator, and re-check the benches. Might be nothing > or not, but '.' is definitely not free. The same for > dispatch_response_iproto, dispatch_response_console. Replied in the parallel thread: https://lists.tarantool.org/pipermail/tarantool-patches/2021-August/025137.html > > - msg, real_end, request.errno = decode_push(body_rpos, body_end) > > 12. decode_push is not unused. Deleted it. The incremental diff is below. -- diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c index 6859e955ac6e..e7cb5b3d810f 100644 --- a/src/box/lua/net_box.c +++ b/src/box/lua/net_box.c @@ -79,79 +79,63 @@ enum netbox_method { }; struct netbox_registry { - /* sync -> netbox_request */ + /** sync -> netbox_request */ struct mh_i64ptr_t *requests; }; struct netbox_request { enum netbox_method method; - /* + /** * Unique identifier needed for matching the request with its response. * Used as a key in the registry. */ uint64_t sync; - /* + /** * The registry this request belongs to or NULL if the request has been * completed. */ struct netbox_registry *registry; - /* Format used for decoding the response (ref incremented). */ + /** Format used for decoding the response (ref incremented). */ struct tuple_format *format; - /* Signaled when the response is received. */ + /** Signaled when the response is received. */ struct fiber_cond cond; - /* + /** * A user-provided buffer to which the response body should be copied. * If NULL, the response will be decoded to Lua stack. */ struct ibuf *buffer; - /* + /** * Lua reference to the buffer. Used to prevent garbage collection in * case the user discards the request. */ int buffer_ref; - /* + /** * Whether to skip MessagePack map header and IPROTO_DATA key when * copying the response body to a user-provided buffer. Ignored if * buffer is not set. */ bool skip_header; - /* Lua references to on_push trigger and its context. */ + /** Lua references to on_push trigger and its context. */ int on_push_ref; int on_push_ctx_ref; - /* - * Reference to the request result or LUA_NOREF if the response hasn't - * been received yet. If the response was decoded to a user-provided - * buffer, the result stores the length of the decoded data. + /** + * Lua reference to the request result or LUA_NOREF if the response + * hasn't been received yet. If the response was decoded to a + * user-provided buffer (see buffer_ref), result_ref stores a Lua + * reference to an integer value that contains the length of the + * decoded data. */ int result_ref; - /* + /** * Error if the request failed (ref incremented). NULL on success or if * the response hasn't been received yet. */ struct error *error; - }; static const char netbox_registry_typename[] = "net.box.registry"; static const char netbox_request_typename[] = "net.box.request"; -static void -netbox_request_create(struct netbox_request *request) -{ - request->method = netbox_method_MAX; - request->sync = -1; - request->registry = NULL; - request->format = NULL; - fiber_cond_create(&request->cond); - request->buffer = NULL; - request->buffer_ref = LUA_REFNIL; - request->skip_header = false; - request->on_push_ref = LUA_REFNIL; - request->on_push_ctx_ref = LUA_REFNIL; - request->result_ref = LUA_NOREF; - request->error = NULL; -} - static void netbox_request_destroy(struct netbox_request *request) { @@ -206,19 +190,19 @@ netbox_request_unregister(struct netbox_request *request) mh_i64ptr_del(h, k, NULL); } -static bool -netbox_request_is_ready(struct netbox_request *request) +static inline bool +netbox_request_is_ready(const struct netbox_request *request) { return request->registry == NULL; } -static void +static inline void netbox_request_signal(struct netbox_request *request) { fiber_cond_broadcast(&request->cond); } -static void +static inline void netbox_request_complete(struct netbox_request *request) { netbox_request_unregister(request); @@ -229,7 +213,7 @@ netbox_request_complete(struct netbox_request *request) * Waits on netbox_request::cond. Subtracts the wait time from the timeout. * Returns false on timeout or if the fiber was cancelled. */ -static bool +static inline bool netbox_request_wait(struct netbox_request *request, double *timeout) { double ts = ev_monotonic_now(loop()); @@ -238,14 +222,14 @@ netbox_request_wait(struct netbox_request *request, double *timeout) return rc == 0; } -static void +static inline void netbox_request_set_result(struct netbox_request *request, int result_ref) { assert(request->result_ref == LUA_NOREF); request->result_ref = result_ref; } -static void +static inline void netbox_request_set_error(struct netbox_request *request, struct error *error) { assert(request->error == NULL); @@ -297,7 +281,7 @@ netbox_registry_destroy(struct netbox_registry *registry) /** * Looks up a request by id (sync). Returns NULL if not found. */ -static struct netbox_request * +static inline struct netbox_request * netbox_registry_lookup(struct netbox_registry *registry, uint64_t sync) { struct mh_i64ptr_t *h = registry->requests; @@ -1637,9 +1621,6 @@ static int netbox_new_request(struct lua_State *L) { struct netbox_request *request = lua_newuserdata(L, sizeof(*request)); - netbox_request_create(request); - luaL_getmetatable(L, netbox_request_typename); - lua_setmetatable(L, -2); struct netbox_registry *registry = luaT_check_netbox_registry(L, 1); request->sync = luaL_touint64(L, 2); request->buffer = (struct ibuf *)lua_topointer(L, 3); @@ -1657,8 +1638,15 @@ netbox_new_request(struct lua_State *L) else request->format = tuple_format_runtime; tuple_format_ref(request->format); - if (netbox_request_register(request, registry) != 0) + fiber_cond_create(&request->cond); + request->result_ref = LUA_NOREF; + request->error = NULL; + if (netbox_request_register(request, registry) != 0) { + netbox_request_destroy(request); luaT_error(L); + } + luaL_getmetatable(L, netbox_request_typename); + lua_setmetatable(L, -2); return 1; } diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua index 1379d04268d9..20dec5648926 100644 --- a/src/box/lua/net_box.lua +++ b/src/box/lua/net_box.lua @@ -68,11 +68,6 @@ local M_INJECT = 17 -- utility tables local is_final_state = {closed = 1, error = 1} -local function decode_push(raw_data) - local response, raw_end = decode(raw_data) - return response[IPROTO_DATA_KEY][1], raw_end -end - local function version_id(major, minor, patch) return bit.bor(bit.lshift(major, 16), bit.lshift(minor, 8), patch) end
next prev parent reply other threads:[~2021-08-04 12:30 UTC|newest] Thread overview: 80+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-07-23 11:07 [Tarantool-patches] [PATCH 00/20] Rewrite performance critical parts of net.box " Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 01/20] net.box: fix console connection breakage when request is discarded Vladimir Davydov via Tarantool-patches 2021-07-28 22:49 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-29 10:40 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 02/20] net.box: wake up wait_result callers " Vladimir Davydov via Tarantool-patches 2021-07-29 10:47 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 03/20] net.box: do not check worker_fiber in request:result, is_ready Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 04/20] net.box: remove decode_push from method_decoder table Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 05/20] net.box: use decode_tuple instead of decode_get Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 06/20] net.box: rename request.ctx to request.format Vladimir Davydov via Tarantool-patches 2021-07-28 22:49 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-29 10:54 ` Vladimir Davydov via Tarantool-patches 2021-07-29 22:39 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-30 8:15 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 07/20] net.box: use integer id instead of method name Vladimir Davydov via Tarantool-patches 2021-07-28 22:50 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-29 11:30 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 08/20] net.box: remove useless encode optimization Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 09/20] net.box: rewrite request encoder in C Vladimir Davydov via Tarantool-patches 2021-07-28 22:51 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-29 14:08 ` Vladimir Davydov via Tarantool-patches 2021-07-29 14:10 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 10/20] lua/utils: make char ptr Lua CTIDs public Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 11/20] net.box: rewrite response decoder in C Vladimir Davydov via Tarantool-patches 2021-07-27 14:07 ` Cyrill Gorcunov via Tarantool-patches 2021-07-27 14:14 ` Vladimir Davydov via Tarantool-patches 2021-07-29 22:39 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-30 8:44 ` Vladimir Davydov via Tarantool-patches 2021-07-30 22:12 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-02 7:36 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 12/20] net.box: rewrite error " Vladimir Davydov via Tarantool-patches 2021-07-30 22:13 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-02 8:00 ` Vladimir Davydov via Tarantool-patches 2021-08-02 21:47 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 13/20] net.box: rewrite send_and_recv_{iproto, console} " Vladimir Davydov via Tarantool-patches 2021-08-02 21:49 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-03 15:44 ` Vladimir Davydov via Tarantool-patches 2021-08-03 23:06 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-04 13:56 ` Vladimir Davydov via Tarantool-patches 2021-08-04 21:18 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-05 8:37 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 14/20] net.box: rename netbox_{prepare, encode}_request to {begin, end} Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 15/20] net.box: rewrite request implementation in C Vladimir Davydov via Tarantool-patches 2021-08-02 21:54 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-04 12:30 ` Vladimir Davydov via Tarantool-patches [this message] 2021-08-04 15:35 ` Vladimir Davydov via Tarantool-patches 2021-08-04 16:14 ` Vladimir Davydov via Tarantool-patches 2021-08-04 21:20 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-05 12:46 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 16/20] net.box: store next_request_id in C code Vladimir Davydov via Tarantool-patches 2021-08-03 23:06 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-04 16:25 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 17/20] net.box: rewrite console handlers in C Vladimir Davydov via Tarantool-patches 2021-08-03 23:07 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-05 11:53 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 18/20] net.box: rewrite iproto " Vladimir Davydov via Tarantool-patches 2021-08-03 23:08 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-05 11:54 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 19/20] net.box: merge new_id, new_request and encode_method Vladimir Davydov via Tarantool-patches 2021-08-03 23:08 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-05 11:55 ` Vladimir Davydov via Tarantool-patches 2021-07-23 11:07 ` [Tarantool-patches] [PATCH 20/20] net.box: do not create request object in Lua for sync requests Vladimir Davydov via Tarantool-patches 2021-08-03 23:09 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-05 12:23 ` Vladimir Davydov via Tarantool-patches 2021-07-23 12:48 ` [Tarantool-patches] [PATCH 00/20] Rewrite performance critical parts of net.box in C Vladimir Davydov via Tarantool-patches 2021-07-26 7:26 ` Kirill Yukhin via Tarantool-patches 2021-07-27 9:59 ` Vladimir Davydov via Tarantool-patches 2021-07-28 22:51 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-29 11:33 ` Vladimir Davydov via Tarantool-patches 2021-07-29 15:23 ` Vladimir Davydov via Tarantool-patches 2021-07-29 22:38 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-30 10:04 ` Vladimir Davydov via Tarantool-patches 2021-07-29 22:40 ` Vladislav Shpilevoy via Tarantool-patches 2021-07-30 8:16 ` Vladimir Davydov via Tarantool-patches 2021-08-03 23:05 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-04 12:40 ` Vladimir Davydov via Tarantool-patches 2021-08-05 20:59 ` Vladislav Shpilevoy via Tarantool-patches 2021-08-09 11:22 ` Igor Munkin via Tarantool-patches 2021-08-09 11:48 ` Vitaliia Ioffe via Tarantool-patches 2021-08-09 13:56 ` Vladimir Davydov via Tarantool-patches
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20210804123001.3cwudybvkw6dds74@esperanza \ --to=tarantool-patches@dev.tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --cc=vdavydov@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH 15/20] net.box: rewrite request implementation in C' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox