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 868B86EC40; Fri, 4 Jun 2021 14:13:57 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 868B86EC40 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1622805237; bh=xlZYhd6UrRcbVQTklZtdoo/r3ONWw60h5kwPy+EIq3k=; h=To:Cc:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=dprQFo3PcaTkOJZkOZ1btxJTjEpqTQU3NH0zfme64LBxziF3Um65zSM4JjvwXFZsa vIEh8SIF1wVHLKuZ3Mvdv5mkNOLcUuoJshMTK0L4ZrvguUfQA8rHMcYTLmSAPLpwWn IBcpb627Dcw/klu0TsQ/+YG5UkqNZT1NtqL5wrcs= Received: from smtp47.i.mail.ru (smtp47.i.mail.ru [94.100.177.107]) (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 BB9296EC40 for ; Fri, 4 Jun 2021 14:13:29 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org BB9296EC40 Received: by smtp47.i.mail.ru with esmtpa (envelope-from ) id 1lp7lY-0007QW-Uf; Fri, 04 Jun 2021 14:13:29 +0300 To: gorcunov@tarantool.org, tarantool-patches@dev.tarantool.org Cc: Egor2001 Date: Fri, 4 Jun 2021 14:13:10 +0300 Message-Id: <8894403bf01395ae2b3082b005ff48178cde3081.1622792861.git.elchinov.es@gmail.com> 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: 4F1203BC0FB41BD9D5B0DA836B685C544BBC2A69B1B4100B389BF69B7A224D7C182A05F5380850403FF3B8899B8DEC570FE93CC27FF25EBBB3C666DDFD8FE9E6F34EDDBF66B084D4 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7A179494B5629353BEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637A69A378178A91E348638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D8160A7ABAA2136DE403536E6923874343117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB2376E601842F6C81A19E625A9149C048EE042285CD7A5C321FE21AE983DBD7FFC1D8FC6C240DEA7642DBF02ECDB25306B2B78CF848AE20165D0A6AB1C7CE11FEE3223C850C947643096136E347CC761E07C4224003CC836476EA7A3FFF5B025636E2021AF6380DFAD1A18204E546F3947CB11811A4A51E3B096D1867E19FE1407959CC434672EE6371089D37D7C0E48F6C8AA50765F7900637B5EAED125435346EEFF80C71ABB335746BA297DBC24807EABDAD6C7F3747799A X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A24209795067102C07E8F7B195E1C97831354DF991D679DE6A38E9427ECC4B679E X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975CC176FDF34A1E429F35696E78A82FC2F1554D654BE1518FE39C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EFD99FB7B2A39B4961699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D3452F7993FB7281BFD5C896EC31F30E27C288B370D7413AB25B5989AB13047320F34CC8A652B5A3FE91D7E09C32AA3244CF64F4E0501308DD4D8BE67D3C9ACE7B11DD47778AE04E04DFACE5A9C96DEB163 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojbL9S8ysBdXjL9XSvACMLmTNrpuueCoYv X-Mailru-Sender: 11C2EC085EDE56FAC07928AF2646A7692E1BED6969B3588A0FE93CC27FF25EBBC479C2914A57FB1F58570E9BDA2331C06F53C80213D1719C2C26F88BABE1618CA23003C376F5F1387402F9BA4338D657ED14614B50AE0675 X-Mras: Ok Subject: [Tarantool-patches] [PATCH 1/2] fiber: add PoC for fiber creation 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 Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" From: Egor2001 For now fiber creation backtrace is stored in the separate subtable of fiber.info called backtrace_parent for convenience. Lua stacks of fiber creation aren't preserved in backtrace yet because of need to somehow handle parent Lua state inside the child fiber for this sake. Backtrace caching and demangling aren't present yet too as this is a proof-of-concept implementation. Needed for: #4002 --- src/lib/core/backtrace.cc | 66 +++++++++++++++++++ src/lib/core/backtrace.h | 6 ++ src/lib/core/fiber.c | 8 +++ src/lib/core/fiber.h | 16 +++++ src/lua/fiber.c | 9 +++ .../gh-4002-fiber-creation-backtrace.result | 55 ++++++++++++++++ .../gh-4002-fiber-creation-backtrace.test.lua | 25 +++++++ 7 files changed, 185 insertions(+) create mode 100644 test/app/gh-4002-fiber-creation-backtrace.result create mode 100644 test/app/gh-4002-fiber-creation-backtrace.test.lua diff --git a/src/lib/core/backtrace.cc b/src/lib/core/backtrace.cc index b4048089f..276933ad6 100644 --- a/src/lib/core/backtrace.cc +++ b/src/lib/core/backtrace.cc @@ -432,6 +432,72 @@ out: free(demangle_buf); } +/** + * Collect up to `limit' IP register values + * for frames of the current stack into `ip_buf'. + * Must be by far faster than usual backtrace according to the + * libunwind doc for unw_backtrace(). + */ +void +fast_trace_collect(void **ip_buf, int limit) +{ + memset(ip_buf, 0, limit * sizeof(*ip_buf)); + unw_backtrace(ip_buf, limit); +} + +/** + * Call `cb' callback for not more than + * first `limit' frames present in the `ip_buf'. + * + * The implementation uses poorly documented `get_proc_name' callback + * from the `unw_accessors_t' to get procedure names via `ip_buf' values. + * Although `get_proc_name' is present on most architectures, it's an optional + * field, so procedure name is allowed to be absent (NULL) in `cb' call. + * + * TODO: to add cache and demangling support + */ +void +fast_trace_foreach(backtrace_cb cb, void **ip_buf, int limit, void *cb_ctx) +{ + static __thread char proc_name[BACKTRACE_NAME_MAX]; + int frame_no = 0; + unw_word_t ip = 0, offset = 0; + unw_proc_info_t pi; + int ret = 0; + char* proc = NULL; + + unw_accessors_t* acc = unw_get_accessors(unw_local_addr_space); + assert(acc); + + for (frame_no = 0; frame_no < limit && ip_buf[frame_no] != NULL; + ++frame_no) { + ip = (unw_word_t)ip_buf[frame_no]; + if (acc->get_proc_name == NULL) { + ret = unw_get_proc_info_by_ip(unw_local_addr_space, + ip, &pi, NULL); + offset = ip - pi.start_ip; + } else { + ret = acc->get_proc_name(unw_local_addr_space, ip, + proc_name, sizeof(proc_name), + &offset, NULL); + proc = proc_name; + } + + if (ret != 0 || (frame_no > 0 && + cb(frame_no - 1, (void *)ip, proc, + (size_t)offset, cb_ctx) != 0)) + break; + } + +#ifndef TARGET_OS_DARWIN + if (ret != 0) + say_debug("unwinding error: %s", unw_strerror(ret)); +#else + if (ret != 0) + say_debug("unwinding error: %i", ret); +#endif +} + void print_backtrace(void) { diff --git a/src/lib/core/backtrace.h b/src/lib/core/backtrace.h index e0ae56be4..1560f03e3 100644 --- a/src/lib/core/backtrace.h +++ b/src/lib/core/backtrace.h @@ -55,6 +55,12 @@ backtrace_foreach(backtrace_cb cb, coro_context *coro_ctx, void *cb_ctx); void backtrace_proc_cache_clear(void); +void +fast_trace_collect(void **ip_buf, int limit); + +void +fast_trace_foreach(backtrace_cb cb, void **ip_buf, int limit, void *cb_ctx); + #endif /* ENABLE_BACKTRACE */ #if defined(__cplusplus) diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index 759c7da6a..73500e043 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -45,6 +45,11 @@ extern void cord_on_yield(void); +#if ENABLE_BACKTRACE +#include "backtrace.h" /* fast_trace */ + +#endif /* ENABLE_BACKTRACE */ + #if ENABLE_FIBER_TOP #include /* __rdtscp() */ @@ -1259,6 +1264,9 @@ fiber_new_ex(const char *name, const struct fiber_attr *fiber_attr, fiber->f = f; fiber->fid = cord->next_fid; fiber_set_name(fiber, name); +#if ENABLE_BACKTRACE + fast_trace_collect(fiber->parent_bt_ip_buf, FIBER_PARENT_BT_MAX); +#endif /* ENABLE_BACKTRACE */ register_fid(fiber); fiber->csw = 0; diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h index 8f4e14796..f5fa31443 100644 --- a/src/lib/core/fiber.h +++ b/src/lib/core/fiber.h @@ -111,6 +111,18 @@ struct cpu_stat { #endif /* ENABLE_FIBER_TOP */ +#if ENABLE_BACKTRACE + +enum { + /** + * Maximum entries count to grab + * from the fiber creation backtrace. + */ + FIBER_PARENT_BT_MAX = 10 +}; + +#endif /* ENABLE_BACKTRACE */ + enum { /** Both limits include terminating 0. */ FIBER_NAME_INLINE = 40, @@ -640,6 +652,10 @@ struct fiber { */ char *name; char inline_name[FIBER_NAME_INLINE]; +#if ENABLE_BACKTRACE + /** Fiber creation backtrace chunk. */ + void* parent_bt_ip_buf[FIBER_PARENT_BT_MAX]; +#endif /* ENABLE_BACKTRACE */ }; /** Invoke on_stop triggers and delete them. */ diff --git a/src/lua/fiber.c b/src/lua/fiber.c index 91898c283..dc7051edd 100644 --- a/src/lua/fiber.c +++ b/src/lua/fiber.c @@ -308,6 +308,15 @@ lbox_fiber_statof_map(struct fiber *f, void *cb_ctx, bool backtrace) backtrace_foreach(fiber_backtrace_cb, 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; + lua_pushstring(L, "backtrace_parent"); + lua_newtable(L); + fast_trace_foreach(fiber_backtrace_cb, f->parent_bt_ip_buf, + FIBER_PARENT_BT_MAX, &tb_ctx); + lua_settable(L, -3); #endif /* ENABLE_BACKTRACE */ } return 0; diff --git a/test/app/gh-4002-fiber-creation-backtrace.result b/test/app/gh-4002-fiber-creation-backtrace.result new file mode 100644 index 000000000..185aec585 --- /dev/null +++ b/test/app/gh-4002-fiber-creation-backtrace.result @@ -0,0 +1,55 @@ +-- test-run result file version 2 +yaml = require('yaml') + | --- + | ... +fiber = require('fiber') + | --- + | ... +test_run = require('test_run').new() + | --- + | ... + +stack_len = 0 + | --- + | ... +parent_stack_len = 0 + | --- + | ... + +test_run:cmd('setopt delimiter ";"') + | --- + | - true + | ... +function foo() + local fiber_info = fiber.info() + local fiber_id = fiber.self():id() + local parent_stack = fiber_info[fiber_id].backtrace_parent + stack_len = stack and #stack or 0 + parent_stack_len = parent_stack and #parent_stack or 0 +end; + | --- + | ... + +function bar() + fiber.create(foo) +end; + | --- + | ... +test_run:cmd('setopt delimiter ""'); + | --- + | - true + | ... + +bar() + | --- + | ... + -- ... -> fiber.create() -> fiber.new() -> fiber.new_ex() + | --- + | ... + -- or backtrace is disabled + | --- + | ... +parent_stack_len > 3 or stack_len == 0 + | --- + | - true + | ... diff --git a/test/app/gh-4002-fiber-creation-backtrace.test.lua b/test/app/gh-4002-fiber-creation-backtrace.test.lua new file mode 100644 index 000000000..c58308eda --- /dev/null +++ b/test/app/gh-4002-fiber-creation-backtrace.test.lua @@ -0,0 +1,25 @@ +yaml = require('yaml') +fiber = require('fiber') +test_run = require('test_run').new() + +stack_len = 0 +parent_stack_len = 0 + +test_run:cmd('setopt delimiter ";"') +function foo() + local fiber_info = fiber.info() + local fiber_id = fiber.self():id() + local parent_stack = fiber_info[fiber_id].backtrace_parent + stack_len = stack and #stack or 0 + parent_stack_len = parent_stack and #parent_stack or 0 +end; + +function bar() + fiber.create(foo) +end; +test_run:cmd('setopt delimiter ""'); + +bar() + -- ... -> fiber.create() -> fiber.new() -> fiber.new_ex() + -- or backtrace is disabled +parent_stack_len > 3 or stack_len == 0 -- 2.31.1