From: Egor Elchinov via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: gorcunov@tarantool.org, alyapunov@tarantool.org Cc: tarantool-patches@dev.tarantool.org, Egor Elchinov <elchinov.es@gmail.com> Subject: [Tarantool-patches] [PATCH v2 4/4] fiber: refactor C backtrace and add changelog Date: Fri, 9 Jul 2021 14:03:53 +0300 [thread overview] Message-ID: <fe6b73a52786c58fbe8151394c5662f8b67362d6.1625827535.git.elchinov.es@gmail.com> (raw) In-Reply-To: <cover.1625827535.git.elchinov.es@gmail.com> From: Egor Elchinov <elchinov.es@gmail.com> 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 | 164 +++++++++++++----- .../gh-4002-fiber-creation-backtrace.result | 4 +- .../gh-4002-fiber-creation-backtrace.test.lua | 4 +- 4 files changed, 132 insertions(+), 48 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 f97c4c0a9..c82aa27af 100644 --- a/src/lib/core/backtrace.cc +++ b/src/lib/core/backtrace.cc @@ -47,7 +47,6 @@ #include <libunwind.h> #ifdef TARGET_OS_DARWIN -#include <execinfo.h> #include <dlfcn.h> #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,51 @@ 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, "%s", name); + + 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; } -error: + + unw_get_reg(unw_cur, UNW_REG_IP, &ip); + if (backtrace_proc_cache_find(ip, &cache_name, offset) == 0) { + return cache_name; + } + + 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 +471,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 <execinfo.h> 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 +508,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 +529,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,17 +567,35 @@ 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); - offset = (char *)ip - (char *)dli.dli_saddr; + if (backtrace_proc_cache_find((unw_word_t)ip, &proc, + &offset) == 0) { + ret = 0; + } else { + ret = dladdr(ip, &dli); + 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
next prev parent reply other threads:[~2021-07-09 11:06 UTC|newest] Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-07-09 11:03 [Tarantool-patches] [PATCH v2 0/4] fiber: introduce creation backtrace Egor Elchinov via Tarantool-patches 2021-07-09 11:03 ` [Tarantool-patches] [PATCH v2 1/4] fiber: add PoC for fiber " Egor Elchinov via Tarantool-patches 2021-07-12 11:42 ` Cyrill Gorcunov via Tarantool-patches 2021-07-09 11:03 ` [Tarantool-patches] [PATCH v2 2/4] fiber: add option and PoC for Lua parent backtrace Egor Elchinov via Tarantool-patches 2021-07-12 12:09 ` Cyrill Gorcunov via Tarantool-patches 2021-07-14 9:29 ` Egor Elchinov via Tarantool-patches 2021-07-09 11:03 ` [Tarantool-patches] [PATCH v2 3/4] fiber: refactor lua backtrace routines Egor Elchinov via Tarantool-patches 2021-07-12 12:13 ` Cyrill Gorcunov via Tarantool-patches 2021-07-14 9:42 ` Egor Elchinov via Tarantool-patches 2021-07-09 11:03 ` Egor Elchinov via Tarantool-patches [this message] 2021-07-12 12:35 ` [Tarantool-patches] [PATCH v2 4/4] fiber: refactor C backtrace and add changelog Cyrill Gorcunov via Tarantool-patches 2021-07-14 9:42 ` Egor Elchinov 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=fe6b73a52786c58fbe8151394c5662f8b67362d6.1625827535.git.elchinov.es@gmail.com \ --to=tarantool-patches@dev.tarantool.org \ --cc=alyapunov@tarantool.org \ --cc=eelchinov@tarantool.org \ --cc=elchinov.es@gmail.com \ --cc=gorcunov@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH v2 4/4] fiber: refactor C backtrace and add changelog' \ /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