From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 84A016EC41; Thu, 1 Jul 2021 23:27:45 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 84A016EC41 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1625171265; bh=uSepN6QnrX4rr/1MO4+TCG3cl9vJ86zlBmoHdr5/8sU=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=ArjI/EeOl+vgvrgsxNzpW+5rjxLNw/kRrYjVnAPnQvzalhDiO1s18Nyyv8a9bDkz2 yLq66K+bV9LsRtt2ZJsHilOOJ5+71dzC+zQuQwPcJ80EpX+dq1DtfibJ8SfTEwWp4T sNY2HxYkyu1pqzB4P5sAkk/Bq3WmPWW2zrtvpI2w= Received: from smtp60.i.mail.ru (smtp60.i.mail.ru [217.69.128.40]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 45D376EC45 for ; Thu, 1 Jul 2021 23:25:50 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 45D376EC45 Received: by smtp60.i.mail.ru with esmtpa (envelope-from ) id 1lz3Ft-0006gg-1D; Thu, 01 Jul 2021 23:25:49 +0300 To: gorcunov@tarantool.org, alyapunov@tarantool.org, skaplun@tarantool.org Date: Thu, 1 Jul 2021 23:24:42 +0300 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD954DFF1DC42D673FB0C620705B15DE32DFE392EA95FA71EAB182A05F53808504017A7A4A0E85AB996CB8691F0D69297131E05CA557702195D7F6D90DF62891D55 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7AB5815F4DE05345AEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637D84D274D72FCF47F8638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D81CB9F80B759AEAD6B2796E79D131ABD1117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BF1175FABE1C0F9B6A471835C12D1D977C4224003CC836476EB9C4185024447017B076A6E789B0E975F5C1EE8F4F765FCA1F6C296CD2042023AA81AA40904B5D9CF19DD082D7633A078D18283394535A93AA81AA40904B5D98AA50765F7900637A5C4BDDDDF34C9AAD81D268191BDAD3D698AB9A7B718F8C4D1B931868CE1C5781A620F70A64A45A98AA50765F79006372E808ACE2090B5E1725E5C173C3A84C3C5EA940A35A165FF2DBA43225CD8A89F616AD31D0D18CD5C6D8C47C27EEC5E9FB5C8C57E37DE458BEDA766A37F9254B7 X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A2368A440D3B0F6089093C9A16E5BC824A2A04A2ABAA09D25379311020FFC8D4ADD39CE08E0D58FA78F79C2BD0AAA3993C X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975CBCA6440478D4BA4627F5CE9A7FA97CE75BE99C077915EA709C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EFCCE3E035A672CDEE699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34C974B02B4EA30DFB911ADBB3D2250BAB9095D1604AB8A3AEB49C9C6AA2E1E34151D6061F4034D1531D7E09C32AA3244C19753041C7DCDF65F510166E14A4223A725D5B54B2FE457583B48618A63566E0 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojbL9S8ysBdXhQbJZ+TAeEv3JFOwScF5qd X-Mailru-Sender: EFA0F3A8419EF2166B053C73E674FFD55D0AAE4F271A179BCE55547417CF2EBCE2527C969975515C67F54F2D6EFFC80BC77752E0C033A69E17841C44D9B5D58765F2F89A5AFDB6F16C18EFA0BB12DBB0 X-Mras: Ok Subject: [Tarantool-patches] [PATCH 4/7] fiber: add PoC for Lua parent backtrace X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Egor Elchinov via Tarantool-patches Reply-To: eelchinov@tarantool.org Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" From: Egor Elchinov From: Egor Elchinov For now Lua backtrace is fully collected at fiber creation moment and stored in a dynamically allocated buffer. Needed for: #4002 --- src/lib/core/fiber.h | 7 ++ src/lua/fiber.c | 168 ++++++++++++++++++++++++++++++++++++++++--- src/lua/fiber.h | 19 +++++ 3 files changed, 185 insertions(+), 9 deletions(-) diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h index beed58866..ce1c83d11 100644 --- a/src/lib/core/fiber.h +++ b/src/lib/core/fiber.h @@ -528,6 +528,7 @@ struct txn; struct credentials; struct lua_State; struct ipc_wait_pad; +struct parent_bt_lua; struct fiber { coro_context ctx; @@ -634,6 +635,12 @@ struct fiber { * Optional fiber.storage Lua reference. */ int ref; +#if ENABLE_BACKTRACE + /** + * Lua parent backtrace (may be NULL) + */ + struct parent_bt_lua *parent_bt; +#endif /* ENABLE_BACKTRACE */ } lua; /** * Iproto sync. diff --git a/src/lua/fiber.c b/src/lua/fiber.c index 7b21361d4..026e30bc6 100644 --- a/src/lua/fiber.c +++ b/src/lua/fiber.c @@ -193,6 +193,18 @@ struct lua_fiber_tb_ctx { int tb_frame; }; +/** + * Lua parent traceback context. + */ +struct lua_parent_tb_ctx { + /* Lua stack to push values. */ + struct lua_State *L; + /* Lua parent backtrace. */ + struct parent_bt_lua *bt; + /* Count of traced frames (both C and Lua). */ + int tb_frame; +}; + #ifdef ENABLE_BACKTRACE static void dump_lua_frame(struct lua_State *L, lua_Debug *ar, int tb_frame) @@ -209,6 +221,22 @@ dump_lua_frame(struct lua_State *L, lua_Debug *ar, int tb_frame) lua_settable(L, -3); } +static void +dump_parent_lua_frame(struct lua_State *L, const char *name, const char *src, + int currentline, int tb_frame) +{ + char buf[512]; + snprintf(buf, sizeof(buf), "%s in %s at line %i", + name != NULL ? name : "(unnamed)", + src, currentline); + lua_pushnumber(L, tb_frame); + lua_newtable(L); + lua_pushstring(L, "L"); + lua_pushstring(L, buf); + lua_settable(L, -3); + lua_settable(L, -3); +} + static int fiber_backtrace_cb(int frameno, void *frameret, const char *func, size_t offset, void *cb_ctx) { @@ -260,7 +288,115 @@ fiber_backtrace_cb(int frameno, void *frameret, const char *func, size_t offset, lua_settable(L, -3); return 0; } -#endif + +static int +fiber_parent_backtrace_cb(int frameno, void *frameret, const char *func, + size_t offset, void *cb_ctx) +{ + int lua_frame = 0; + struct lua_parent_tb_ctx *tb_ctx = (struct lua_parent_tb_ctx *)cb_ctx; + struct parent_bt_lua *bt = tb_ctx->bt; + struct lua_State *L = tb_ctx->L; + /* + * There is impossible to get func == NULL until + * https://github.com/tarantool/tarantool/issues/5326 + * will not resolved, but is possible afterwards. + */ + if (bt != NULL && func != NULL && strstr(func, "lj_BC_FUNCC") == func) { + /* We are in the LUA vm. */ + while (lua_frame < bt->cnt) { + tb_ctx->tb_frame++; + dump_parent_lua_frame(L, bt->names[lua_frame], + bt->sources[lua_frame], + bt->lines[lua_frame], + tb_ctx->tb_frame); + lua_frame++; + } + } + char buf[512]; + int l = snprintf(buf, sizeof(buf), "#%-2d %p in ", frameno, frameret); + if (func) + snprintf(buf + l, sizeof(buf) - l, "%s+%zu", func, offset); + else + snprintf(buf + l, sizeof(buf) - l, "?"); + tb_ctx->tb_frame++; + lua_pushnumber(L, tb_ctx->tb_frame); + lua_newtable(L); + lua_pushstring(L, "C"); + lua_pushstring(L, buf); + lua_settable(L, -3); + lua_settable(L, -3); + return 0; +} + +static int +fiber_parent_bt_init(struct fiber *f, struct lua_State *L) +{ + int lua_frame = 0, tb_frame = 0; + lua_Debug ar; + struct parent_bt_lua *bt = NULL; + + bt = (struct parent_bt_lua *)malloc(sizeof(*bt)); + if (bt == NULL){ + diag_set(OutOfMemory, sizeof(*bt), "malloc", "bt"); + return 1; + } + + while (tb_frame < PARENT_BT_LUA_LEN_MAX && + lua_getstack(L, lua_frame, &ar) > 0) { + /* Skip all following C-frames. */ + lua_getinfo(L, "Sln", &ar); + if (*ar.what != 'C') + break; + if (ar.name != NULL) { + /* Dump frame if it is a C built-in call. */ + bt->lines[tb_frame] = ar.currentline; + memset(bt->names[tb_frame], 0, + PARENT_BT_LUA_NAME_MAX); + strncpy(bt->names[tb_frame], ar.name, + PARENT_BT_LUA_NAME_MAX - 1); + memset(bt->sources[tb_frame], 0, + PARENT_BT_LUA_NAME_MAX); + strncpy(bt->sources[tb_frame], ar.source, + PARENT_BT_LUA_NAME_MAX - 1); + tb_frame++; + } + lua_frame++; + } + while (tb_frame < PARENT_BT_LUA_LEN_MAX && + lua_getstack(L, lua_frame, &ar) > 0) { + /* Trace Lua frame. */ + lua_getinfo(L, "Sln", &ar); + if (*ar.what == 'C') + break; + bt->lines[tb_frame] = ar.currentline; + memset(bt->names[tb_frame], 0, PARENT_BT_LUA_NAME_MAX); + if (ar.name != NULL) { + strncpy(bt->names[tb_frame], ar.name, + PARENT_BT_LUA_NAME_MAX - 1); + } else { + strncpy(bt->names[tb_frame], "(unnamed)", + PARENT_BT_LUA_NAME_MAX - 1); + } + memset(bt->sources[tb_frame], 0, PARENT_BT_LUA_NAME_MAX); + strncpy(bt->sources[tb_frame], ar.source, + PARENT_BT_LUA_NAME_MAX - 1); + tb_frame++; + lua_frame++; + } + + bt->cnt = tb_frame; + f->storage.lua.parent_bt = bt; + + return 0; +} + +static void +fiber_parent_bt_free(struct fiber *f) +{ + free(f->storage.lua.parent_bt); +} +#endif /* ENABLE_BACKTRACE */ static int lbox_fiber_statof_map(struct fiber *f, void *cb_ctx, bool backtrace) @@ -299,6 +435,7 @@ lbox_fiber_statof_map(struct fiber *f, void *cb_ctx, bool backtrace) if (backtrace) { #ifdef ENABLE_BACKTRACE struct lua_fiber_tb_ctx tb_ctx; + struct lua_parent_tb_ctx parent_tb_ctx; tb_ctx.L = L; tb_ctx.R = f->storage.lua.stack; tb_ctx.lua_frame = 0; @@ -309,14 +446,14 @@ lbox_fiber_statof_map(struct fiber *f, void *cb_ctx, bool backtrace) f != fiber() ? &f->ctx : NULL, &tb_ctx); lua_settable(L, -3); - tb_ctx.lua_frame = 0; - tb_ctx.tb_frame = 0; - tb_ctx.R = NULL; + parent_tb_ctx.L = L; + parent_tb_ctx.bt = f->storage.lua.parent_bt; + parent_tb_ctx.tb_frame = 0; lua_pushstring(L, "backtrace_parent"); lua_newtable(L); - backtrace_foreach_ip(fiber_backtrace_cb, + backtrace_foreach_ip(fiber_parent_backtrace_cb, f->parent_bt_ip_buf, - FIBER_PARENT_BT_MAX, &tb_ctx); + FIBER_PARENT_BT_MAX, &parent_tb_ctx); lua_settable(L, -3); #endif /* ENABLE_BACKTRACE */ } @@ -481,10 +618,14 @@ lua_fiber_run_f(MAYBE_UNUSED va_list ap) * We can unref child stack here, * otherwise we have to unref child stack in join */ - if (f->flags & FIBER_IS_JOINABLE) + if (f->flags & FIBER_IS_JOINABLE) { lua_pushinteger(L, coro_ref); - else + } else { +#ifdef ENABLE_BACKTRACE + fiber_parent_bt_free(f); +#endif luaL_unref(L, LUA_REGISTRYINDEX, coro_ref); + } return result; } @@ -506,6 +647,11 @@ fiber_create(struct lua_State *L) luaT_error(L); } +#ifdef ENABLE_BACKTRACE + // TODO: error handling + fiber_parent_bt_init(f, L); +#endif + /* Move the arguments to the new coro */ lua_xmove(L, child_L, lua_gettop(L)); /* XXX: 'fiber' is leaked if this throws a Lua error. */ @@ -886,8 +1032,12 @@ lbox_fiber_join(struct lua_State *L) lua_xmove(child_L, L, num_ret); } } - if (child_L != NULL) + if (child_L != NULL) { +#ifdef ENABLE_BACKTRACE + fiber_parent_bt_free(fiber); +#endif luaL_unref(L, LUA_REGISTRYINDEX, coro_ref); + } return num_ret + 1; } diff --git a/src/lua/fiber.h b/src/lua/fiber.h index e29898706..450840fb0 100644 --- a/src/lua/fiber.h +++ b/src/lua/fiber.h @@ -36,6 +36,25 @@ extern "C" { struct lua_State; +/** + * Maximal name length (including '\0') + * and backtrace length. + */ +enum { + PARENT_BT_LUA_NAME_MAX = 64, + PARENT_BT_LUA_LEN_MAX = 8 +}; + +/** + * Stores lua parent backtrace for fiber. + */ +struct parent_bt_lua { + int cnt; + char names[PARENT_BT_LUA_LEN_MAX][PARENT_BT_LUA_NAME_MAX]; + char sources[PARENT_BT_LUA_LEN_MAX][PARENT_BT_LUA_NAME_MAX]; + int lines[PARENT_BT_LUA_LEN_MAX]; +}; + /** * Initialize box.fiber system */ -- 2.31.1