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 A64656EC55; Wed, 14 Jul 2021 14:15:36 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org A64656EC55 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1626261336; bh=UDjpqXKK7okyCpTmB59rL+Atm4P/+DCX2GQPX9b122E=; 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=PntIGPt9ga3wbLHDXPvmXwJU8gOYIk4GPK/hnHpw77SstFBKc2ZUzrU7k3FiE2LhW EKvlPl3gvNEPR/FegorzhAzG0HuYOC037TN8wgUtNBa/3PSW9UAELvbjll4VA8Dcw+ hBqkQuveqB8E8NE9sKzNdCrc3Z5k0vAovj+6iycg= Received: from smtp59.i.mail.ru (smtp59.i.mail.ru [217.69.128.39]) (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 57A3E6EC5A for ; Wed, 14 Jul 2021 14:13:38 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 57A3E6EC5A Received: by smtp59.i.mail.ru with esmtpa (envelope-from ) id 1m3cpd-0001Jt-Fs; Wed, 14 Jul 2021 14:13:38 +0300 To: gorcunov@tarantool.org, alyapunov@tarantool.org Cc: tarantool-patches@dev.tarantool.org, Egor Elchinov Date: Wed, 14 Jul 2021 14:12:52 +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: 4F1203BC0FB41BD97BB0EF39AD2B33D5CFD6F66580F08A9EEA70CBC893E637A3182A05F53808504042C567D1973FEEDFA489B25D0B8D1DF513C0FF42B142EDC67FDD1647781FEF09 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE742D9BD90C58D50E0EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F790063706922F90966A37BA8638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D87325972497D9651858BCA07ABB60B6F9117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB2376E601842F6C81A19E625A9149C048EE902A1BE408319B291DBC1C451FC279AAD8FC6C240DEA7642DBF02ECDB25306B2B78CF848AE20165D0A6AB1C7CE11FEE31F9513A7CA91E5556136E347CC761E07C4224003CC836476EA7A3FFF5B025636E2021AF6380DFAD1A18204E546F3947CB11811A4A51E3B096D1867E19FE1407959CC434672EE6371089D37D7C0E48F6C8AA50765F790063717E6A56809D3D6D1EFF80C71ABB335746BA297DBC24807EABDAD6C7F3747799A X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975CE68746B1F2AB10C6A2E8B119AA9D65E1BA1A1EBA131835879C2B6934AE262D3EE7EAB7254005DCED114C52B35DBB74F4E7EAB7254005DCEDA5DF9383870C0FED1E0A4E2319210D9B64D260DF9561598FCFFBF5018520E39817A45118377F5F9E8E8E86DC7131B365E7726E8460B7C23C X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34A9873270276D43340FB24EF856BC5C17E97DDFD2E301807A6D73D1EA2B50EBC2D8928C90C5F3399A1D7E09C32AA3244C1987E0D0F02550CE3AA0D85A5834A4B7B018FE5BB746DCD1927AC6DF5659F194 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojDdSFIg49M1Rpxff2GRGc0Q== X-Mailru-Sender: EFA0F3A8419EF2166B053C73E674FFD5F481BAE092003380DE3368E14BCC0A51E2527C969975515C67F54F2D6EFFC80BC77752E0C033A69E17841C44D9B5D58765F2F89A5AFDB6F16C18EFA0BB12DBB0 X-Mras: Ok Subject: [Tarantool-patches] [PATCH v3 4/4] fiber: refactor C backtrace and add changelog 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: Egor Elchinov Backtrace cache support and cxx demangling added. DWARF version and lua test fixed to support specific platforms. Changelog added. Closes: #4002 --- .../gh-4002-fiber-creation-backtrace.md | 8 + src/lib/core/backtrace.cc | 169 +++++++++++++----- .../gh-4002-fiber-creation-backtrace.result | 4 +- .../gh-4002-fiber-creation-backtrace.test.lua | 4 +- 4 files changed, 135 insertions(+), 50 deletions(-) create mode 100644 changelogs/unreleased/gh-4002-fiber-creation-backtrace.md diff --git a/changelogs/unreleased/gh-4002-fiber-creation-backtrace.md b/changelogs/unreleased/gh-4002-fiber-creation-backtrace.md new file mode 100644 index 000000000..1e1ac177a --- /dev/null +++ b/changelogs/unreleased/gh-4002-fiber-creation-backtrace.md @@ -0,0 +1,8 @@ +## feature/fiber + + * Added new subtable `parent_backtrace` to the `fiber.info()` + containing C and Lua backtrace chunks of fiber creation. + * Added `fiber.parent_bt_enable()` and `fiber.parent_bt_disable()` + options in order to switch on/off the ability to collect + parent backtraces for newly created fibers and to + show/hide `parent_backtrace` subtables in the `fiber.info()`. diff --git a/src/lib/core/backtrace.cc b/src/lib/core/backtrace.cc index ef8a70f1b..355b25d7e 100644 --- a/src/lib/core/backtrace.cc +++ b/src/lib/core/backtrace.cc @@ -47,7 +47,6 @@ #include #ifdef TARGET_OS_DARWIN -#include #include #endif @@ -79,19 +78,29 @@ backtrace_proc_cache_clear(void) proc_cache = NULL; } -const char * -get_proc_name(unw_cursor_t *unw_cur, unw_word_t *offset, bool skip_cache) +int +backtrace_proc_cache_find(unw_word_t ip, const char **name, unw_word_t *offset) { - static __thread char proc_name[BACKTRACE_NAME_MAX]; - unw_word_t ip; - unw_get_reg(unw_cur, UNW_REG_IP, &ip); + struct proc_cache_entry *entry; + mh_int_t k; - if (skip_cache) { - unw_get_proc_name(unw_cur, proc_name, sizeof(proc_name), - offset); - return proc_name; + if (proc_cache != NULL) { + k = mh_i64ptr_find(proc_cache, ip, NULL); + if (k != mh_end(proc_cache)) { + entry = (struct proc_cache_entry *) + mh_i64ptr_node(proc_cache, k)->val; + *offset = entry->offset; + *name = entry->name; + return 0; + } } + return -1; +} + +int +backtrace_proc_cache_put(unw_word_t ip, const char *name, unw_word_t offset) +{ struct proc_cache_entry *entry; struct mh_i64ptr_node_t node; mh_int_t k; @@ -99,39 +108,52 @@ get_proc_name(unw_cursor_t *unw_cur, unw_word_t *offset, bool skip_cache) if (proc_cache == NULL) { region_create(&cache_region, &cord()->slabc); proc_cache = mh_i64ptr_new(); - if (proc_cache == NULL) { - unw_get_proc_name(unw_cur, proc_name, sizeof(proc_name), - offset); - goto error; - } + if (proc_cache == NULL) + return -1; + } + + size_t size; + entry = region_alloc_object(&cache_region, typeof(*entry), + &size); + if (entry == NULL) + return -1; + + node.key = ip; + node.val = entry; + entry->offset = offset; + snprintf(entry->name, BACKTRACE_NAME_MAX - 1, "%s", name); + entry->name[BACKTRACE_NAME_MAX - 1] = 0; + + k = mh_i64ptr_put(proc_cache, &node, NULL, NULL); + if (k == mh_end(proc_cache)) { + size_t used = region_used(&cache_region); + region_truncate(&cache_region, used - size); + return -1; } - k = mh_i64ptr_find(proc_cache, ip, NULL); - if (k != mh_end(proc_cache)) { - entry = (struct proc_cache_entry *) - mh_i64ptr_node(proc_cache, k)->val; - snprintf(proc_name, BACKTRACE_NAME_MAX, "%s", entry->name); - *offset = entry->offset; - } else { + return 0; +} + +const char * +get_proc_name(unw_cursor_t *unw_cur, unw_word_t *offset, bool skip_cache) +{ + static __thread char proc_name[BACKTRACE_NAME_MAX]; + const char *cache_name; + unw_word_t ip; + + if (skip_cache) { unw_get_proc_name(unw_cur, proc_name, sizeof(proc_name), offset); - size_t size; - entry = region_alloc_object(&cache_region, typeof(*entry), - &size); - if (entry == NULL) - goto error; - node.key = ip; - node.val = entry; - snprintf(entry->name, BACKTRACE_NAME_MAX, "%s", proc_name); - entry->offset = *offset; - - k = mh_i64ptr_put(proc_cache, &node, NULL, NULL); - if (k == mh_end(proc_cache)) { - free(entry); - goto error; - } + return proc_name; + } + + unw_get_reg(unw_cur, UNW_REG_IP, &ip); + if (backtrace_proc_cache_find(ip, &cache_name, offset) == 0) { + return cache_name; } -error: + + unw_get_proc_name(unw_cur, proc_name, sizeof(proc_name), offset); + backtrace_proc_cache_put(ip, proc_name, *offset); return proc_name; } @@ -450,7 +472,25 @@ backtrace_collect_ip(void **ip_buf, int limit) #ifndef TARGET_OS_DARWIN unw_backtrace(ip_buf, limit); #else - backtrace(ip_buf, limit); + /* + * This dumb implementation was chosen because the DARWIN + * lacks unw_backtrace() routine from libunwind and + * usual backtrace() from has less capabilities + * than the libunwind version which uses DWARF. + */ + unw_cursor_t unw_cur; + unw_context_t unw_ctx; + int frame_no = 0; + unw_word_t ip; + + unw_getcontext(&unw_ctx); + unw_init_local(&unw_cur, &unw_ctx); + + while (frame_no < limit && unw_step(&unw_cur) > 0) { + unw_get_reg(&unw_cur, UNW_REG_IP, &ip); + ip_buf[frame_no] = (void *)ip; + ++frame_no; + } #endif } @@ -469,12 +509,15 @@ void backtrace_foreach_ip(backtrace_cb cb, void **ip_buf, int limit, void *cb_ctx) { + int demangle_status; + char *demangle_buf = NULL; + size_t demangle_buf_len = 0; #ifndef TARGET_OS_DARWIN char proc_name[BACKTRACE_NAME_MAX]; unw_word_t ip = 0, offset = 0; unw_proc_info_t pi; int frame_no, ret = 0; - char *proc = NULL; + const char *proc = NULL; unw_accessors_t *acc = unw_get_accessors(unw_local_addr_space); @@ -487,21 +530,37 @@ backtrace_foreach_ip(backtrace_cb cb, void **ip_buf, int limit, frame_no++) { ip = (unw_word_t)ip_buf[frame_no]; - if (acc->get_proc_name == NULL) { + if (backtrace_proc_cache_find(ip, &proc, &offset) == 0) { + ret = 0; + } else 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; + proc = NULL; + backtrace_proc_cache_put(ip, proc, offset); } else { ret = acc->get_proc_name(unw_local_addr_space, ip, proc_name, sizeof(proc_name), &offset, NULL); proc = proc_name; + backtrace_proc_cache_put(ip, proc, offset); + } + + if (proc != NULL) { + char *cxxname = abi::__cxa_demangle(proc, demangle_buf, + &demangle_buf_len, + &demangle_status); + if (cxxname != NULL) { + demangle_buf = cxxname; + proc = cxxname; + } } if (ret != 0 || cb(frame_no - 1, (void *)ip, proc, (size_t)offset, cb_ctx) != 0) break; } + free(demangle_buf); if (ret != 0) say_debug("unwinding error: %s", unw_strerror(ret)); #else @@ -509,19 +568,37 @@ backtrace_foreach_ip(backtrace_cb cb, void **ip_buf, int limit, void *ip = NULL; size_t offset = 0; Dl_info dli; + const char *proc = NULL; for (frame_no = 1; frame_no < limit && ip_buf[frame_no] != NULL; ++frame_no) { ip = ip_buf[frame_no]; - ret = dladdr(ip, &dli); - if (ret == 0) - break; - offset = (char *)ip - (char *)dli.dli_saddr; + if (backtrace_proc_cache_find((unw_word_t)ip, &proc, + &offset) == 0) { + ret = 1; + } else { + ret = dladdr(ip, &dli); + if (ret == 0) + break; + offset = (char *)ip - (char *)dli.dli_saddr; + proc = dli.dli_sname; + backtrace_proc_cache_put((unw_word_t)ip, proc, offset); + } - if (cb(frame_no - 1, ip, dli.dli_sname, offset, cb_ctx) != 0) + if (proc != NULL) { + char *cxxname = abi::__cxa_demangle(proc, demangle_buf, + &demangle_buf_len, + &demangle_status); + if (cxxname != NULL) { + demangle_buf = cxxname; + proc = cxxname; + } + } + if (cb(frame_no - 1, ip, proc, offset, cb_ctx) != 0) break; } + free(demangle_buf); if (ret == 0) say_debug("unwinding error: %i", ret); #endif diff --git a/test/app/gh-4002-fiber-creation-backtrace.result b/test/app/gh-4002-fiber-creation-backtrace.result index 6a075911d..91b0cb9ce 100644 --- a/test/app/gh-4002-fiber-creation-backtrace.result +++ b/test/app/gh-4002-fiber-creation-backtrace.result @@ -9,10 +9,10 @@ test_run = require('test_run').new() | --- | ... -local stack_len = 0 +stack_len = 0 | --- | ... -local parent_stack_len = 0 +parent_stack_len = 0 | --- | ... diff --git a/test/app/gh-4002-fiber-creation-backtrace.test.lua b/test/app/gh-4002-fiber-creation-backtrace.test.lua index 79a516860..3c39bb48e 100644 --- a/test/app/gh-4002-fiber-creation-backtrace.test.lua +++ b/test/app/gh-4002-fiber-creation-backtrace.test.lua @@ -2,8 +2,8 @@ yaml = require('yaml') fiber = require('fiber') test_run = require('test_run').new() -local stack_len = 0 -local parent_stack_len = 0 +stack_len = 0 +parent_stack_len = 0 test_run:cmd('setopt delimiter ";"') foo = function() -- 2.31.1