<HTML><BODY><div><div><div>>> -AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer -fno-stack-protector)</div><div>>> +AppendFlags(CMAKE_C_FLAGS -fno-stack-protector)</div><div>></div><div>>Just interesting: how much it drops the performance for C part.</div></div><div> </div><div><div>Not that much. I've tested it with the following script:</div><div>=================================================================</div><div>local function payload()</div><div>  local function fib(n)</div><div>    if n <= 1 then</div><div>      return n</div><div>    end</div><div>    return fib(n - 1) + fib(n - 2)</div><div>  end</div><div>  for i = 1, 1e3 do fib(32) end</div><div>end</div></div><div> </div><div><div>local function generate_output(opts)</div><div>  --local res, err = misc.sysprof.start(opts)</div><div>  --assert(res, err)</div></div><div> </div><div><div>  payload()</div></div><div> </div><div><div>  --res,err = misc.sysprof.stop()</div><div>  --assert(res, err)</div><div>end</div></div><div> </div><div><div>local function check_mode(mode, interval)</div><div>  local res = pcall(</div><div>    generate_output,</div><div>    { mode = mode, interval = interval, path = 'sysprof.bin' }</div><div>  )</div><div>end</div></div><div> </div><div><div>check_mode('C', 1)</div><div>=================================================================</div></div><div> </div><div><div>With FP & sysprof running:</div><div>./src/luajit ../test.lua  19,12s user 0,07s system 99% cpu 19,225 total</div><div>./src/luajit ../test.lua  20,03s user 0,08s system 99% cpu 20,129 total</div><div>./src/luajit ../test.lua  19,82s user 0,09s system 99% cpu 19,927 total</div></div><div> </div><div><div>With FP & sysprof disabled:</div><div>./src/luajit ../test.lua  18,08s user 0,00s system 99% cpu 18,087 total</div><div>./src/luajit ../test.lua  17,89s user 0,00s system 99% cpu 17,904 total</div><div>./src/luajit ../test.lua  18,04s user 0,00s system 99% cpu 18,055 total</div></div><div> </div><div><div>Without FP & sysprof disabled:</div><div>./src/luajit ../test.lua  17,90s user 0,00s system 99% cpu 17,902 total</div><div>./src/luajit ../test.lua  19,02s user 0,00s system 99% cpu 19,031 total</div><div>./src/luajit ../test.lua  17,80s user 0,00s system 99% cpu 17,810 total</div></div><div> </div><div><div>>> @@ -188,6 +183,37 @@ endif()</div><div>>> option(LUAJIT_DISABLE_SYSPROF "LuaJIT platform and Lua profiler support" OFF)</div><div>>> if(LUAJIT_DISABLE_SYSPROF)</div><div>>> AppendFlags(TARGET_C_FLAGS -DLUAJIT_DISABLE_SYSPROF)</div><div>>> + AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer)</div><div>>> +else()</div><div>>> + if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND</div><div>>> + (</div><div>>> + CMAKE_SYSTEM_PROCESSOR STREQUAL "i386" OR</div><div>>> + CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" OR</div><div>>> + CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64"</div><div>>> + )</div><div>>> + )</div><div>>> + # XXX: Libunwind can be provided externally.</div><div>>> + if(NOT LIBUNWIND_LIBRARIES)</div><div>>> + find_package(LibUnwind MODULE QUIET)</div><div>>> + endif()</div><div>>> +</div><div>>> + if(NOT LIBUNWIND_FOUND AND NOT LIBUNWIND_LIBRARIES)</div><div>>> + set(LUAJIT_DISABLE_SYSPROF ON)</div><div>>> + AppendFlags(TARGET_C_FLAGS -DLUAJIT_DISABLE_SYSPROF)</div><div>>> + AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer)</div><div>>> + message(STATUS "Libunwind was not found, sysprof is disabled")</div><div>>> +</div><div>>> + # XXX: CMake sets those variables globally, so using the `unset` here</div><div>>> + # doesn't really clear them out of the parent scope. As stated in the</div><div>>> + # `unset` documentation, to force a variable reference of the form ${VAR}</div><div>>> + # to return an empty string, you need to use `set(<variable> "")`.</div><div>>> + set(LIBUNWIND_INCLUDE_DIR "" PARENT_SCOPE)</div><div>>> + set(LIBUNWIND_LIBRARIES "" PARENT_SCOPE)</div><div>>> + set(LIBUNWIND_FOUND FALSE PARENT_SCOPE)</div><div>>> + else()</div><div>>> + AppendFlags(CMAKE_C_FLAGS -fno-omit-frame-pointer -fasynchronous-unwind-tables)</div><div>>> + endif()</div><div>>> + endif()</div><div>>> endif()</div><div>>Maybe it is better to move this logic to <cmake/LibUnwind.cmake> or</div><div>>something named like that. <CMakeLists.txt> is only about to set</div><div>>options and flags. Not such logic, IMO.</div><div>Moving it to a separate module breaks the PARENT_SCOPE cleanup,</div><div>which is vital for builds inside Tarantool.</div></div><div> </div><div><div>></div><div>> diff --git a/cmake/FindLibUnwind.cmake b/cmake/FindLibUnwind.cmake</div><div>> new file mode 100644</div><div>> index 00000000..70221c12</div><div>> --- /dev/null</div><div>> +++ b/cmake/FindLibUnwind.cmake</div></div><div> </div><div><div>> +if(BUILD_STATIC AND NOT APPLE)</div><div>> + set(LIBUNWIND_LIBRARY_NAME libunwind.a)</div><div>> +else()</div><div>> + # Only a dynamic version of libunwind is available on macOS: also, we</div><div>>> + # should link against the umbrella framework `System` — otherwise `ld` will</div><div>>What is "umberlla framework `System`"?</div><div>https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html</div></div><div> </div><div><div>>> + # complain that it cannot link directly with libunwind.tbd.</div><div>>What is libunwind.tbd?</div><div>A TBD file is a text-based file used by Apple. It contains</div><div>information about a .DYLIB library, the location of the DYLIB</div><div>library, and symbols.</div></div><div> </div><div><div>>> +if(BUILD_STATIC)</div><div>>> + # libunwind could have been built with liblzma dependency:</div><div>></div><div>>Do we need it? And why?</div><div>I took that potion of CMake verbatim from the tarantool/tarantool repo,</div><div>but I see no issues with that part whatsoever. There is no guarantees</div><div>about the format of unwind info in external dynamic libraries and their</div><div>symbol tables can be lzma-compressed.</div></div><div> </div><div><div>>> diff --git a/test/tarantool-tests/misclib-sysprof-capi.test.lua b/test/tarantool-tests/misclib-sysprof-capi.test.lua</div><div>>> index afb99cf2..a5c5b77d 100644</div><div>>> --- a/test/tarantool-tests/misclib-sysprof-capi.test.lua</div><div>>> +++ b/test/tarantool-tests/misclib-sysprof-capi.test.lua</div><div>>> @@ -1,10 +1,11 @@</div><div>>> -- Sysprof is implemented for x86 and x64 architectures only.</div><div>>> local ffi = require("ffi")</div><div>>> +-- luacheck: globals is_excluded</div><div>></div><div>>> require("utils").skipcond(</div><div>>> jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux"</div><div>>> - or ffi.abi("gc64"),</div><div>>> + or ffi.abi("gc64") or is_excluded(),</div><div>></div><div>>Should we delete all others conditions, as far as sysprof is disabled</div><div>for other arches?</div><div>IMO, it is better to leave it as it is for clarity reasons.</div><div>Otherwise, those changes are to cause a lot of headache during</div><div>the test system reorganization that we are willing to do.</div></div><div> </div></div><div> </div><div> </div><div data-signature-widget="container"><div data-signature-widget="content"><div>--<br>Best regards,</div><div>Maxim Kokryashkin</div></div></div><div> </div><div> </div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;">Вторник, 6 декабря 2022, 9:47 +03:00 от Maxim Kokryashkin <max.kokryashkin@gmail.com>:<br> <div id=""><div class="js-helper js-readmsg-msg"><div><div id="style_16703092371123210901_BODY">`backtrace` fails to unwind the host stack in LuaJIT, since there are<br>no frame pointers during the vm calls. Sometimes, those failures cause<br>crashes. This commit replaces it with the libunwind-based unwinder,<br>which makes use of additional runtime info to provide robust unwinding<br>without any frame pointers.<br><br>Also, this commit enables C API tests, which used to crash with<br>`backtrace`.<br><br>The `lj-603-err-snap-restore.test.lua` was updated to correspond with<br>the new size of the `arg` table.<br><br>Part of tarantool/tarantool#781<br>---<br>Changes in v2:<br>- Fixed comments as per review by Sergey<br>- Fixed build for Makefile.original<br>- Moved `is_exluded` to `utils` module<br><br> CMakeLists.txt | 48 ++++++++--<br> cmake/FindLibUnwind.cmake | 87 +++++++++++++++++++<br> cmake/GetLibUnwindVersion.cmake | 12 +++<br> src/CMakeLists.txt | 4 +<br> src/Makefile.original | 10 +++<br> src/lj_sysprof.c | 57 +++++++++---<br> test/tarantool-tests/CMakeLists.txt | 7 ++<br> ...4-add-proto-trace-sysprof-default.test.lua | 5 +-<br> .../lj-603-err-snap-restore.test.lua | 2 +-<br> .../misclib-sysprof-capi.test.lua | 14 ++-<br> .../misclib-sysprof-lapi.test.lua | 7 +-<br> test/tarantool-tests/utils.lua | 39 +++++++++<br> 12 files changed, 259 insertions(+), 33 deletions(-)<br> create mode 100644 cmake/FindLibUnwind.cmake<br> create mode 100644 cmake/GetLibUnwindVersion.cmake<br><br>diff --git a/CMakeLists.txt b/CMakeLists.txt<br>index c870cce2..2ac32465 100644<br>--- a/CMakeLists.txt<br>+++ b/CMakeLists.txt<br>@@ -91,12 +91,9 @@ if(CMAKE_LIBRARY_ARCHITECTURE)<br>   AppendFlags(TARGET_C_FLAGS -DLUA_MULTILIB='"lib/${CMAKE_LIBRARY_ARCHITECTURE}"')<br> endif()<br> <br>-# Since the assembler part does NOT maintain a frame pointer, it's<br>-# pointless to slow down the C part by not omitting it. Debugging,<br>-# tracebacks and unwinding are not affected -- the assembler part<br>-# has frame unwind information and GCC emits it where needed (x64)<br>-# or with -g.<br>-AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer -fno-stack-protector)<br>+AppendFlags(CMAKE_C_FLAGS -fno-stack-protector)<br>+# The '-fomit-frame-pointer` is set depending on sysprof<br>+# and libunwind support.<br> <br> # Redefined to benefit from expanding macros in gdb.<br> set(CMAKE_C_FLAGS_DEBUG "-g -ggdb3")<br>@@ -195,6 +192,45 @@ endif()<br> option(LUAJIT_DISABLE_SYSPROF "LuaJIT platform and Lua profiler support" OFF)<br> if(LUAJIT_DISABLE_SYSPROF)<br>   AppendFlags(TARGET_C_FLAGS -DLUAJIT_DISABLE_SYSPROF)<br>+ AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer)<br>+else()<br>+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND<br>+ (<br>+ CMAKE_SYSTEM_PROCESSOR STREQUAL "i386" OR<br>+ CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" OR<br>+ CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64"<br>+ )<br>+ )<br>+ # XXX: Libunwind can be provided externally.<br>+ if(NOT LIBUNWIND_LIBRARIES)<br>+ find_package(LibUnwind MODULE QUIET)<br>+ endif()<br>+<br>+ if(NOT LIBUNWIND_FOUND AND NOT LIBUNWIND_LIBRARIES)<br>+ set(LUAJIT_DISABLE_SYSPROF ON)<br>+ AppendFlags(TARGET_C_FLAGS -DLUAJIT_DISABLE_SYSPROF)<br>+<br>+ # Since the assembler part does NOT maintain a frame<br>+ # pointer, it's pointless to slow down the C part by not<br>+ # omitting it. Debugging, tracebacks and unwinding are not<br>+ # affected -- the assembler part has frame unwind<br>+ # information and GCC emits it where needed (x64) or<br>+ # with -g.<br>+ AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer)<br>+ message(STATUS "Libunwind was not found, sysprof is disabled")<br>+<br>+ # XXX: CMake sets those variables globally, so using the<br>+ # `unset` here doesn't really clear them out of the parent<br>+ # scope. As stated in the `unset` documentation, to force<br>+ # a variable reference of the form ${VAR} to return an<br>+ # empty string, you need to use `set(<variable> "")`.<br>+ set(LIBUNWIND_INCLUDE_DIR "" PARENT_SCOPE)<br>+ set(LIBUNWIND_LIBRARIES "" PARENT_SCOPE)<br>+ set(LIBUNWIND_FOUND FALSE PARENT_SCOPE)<br>+ else()<br>+ AppendFlags(CMAKE_C_FLAGS -fno-omit-frame-pointer -fasynchronous-unwind-tables)<br>+ endif()<br>+ endif()<br> endif()<br> <br> # Switch to harder (and slower) hash function when a collision<br>diff --git a/cmake/FindLibUnwind.cmake b/cmake/FindLibUnwind.cmake<br>new file mode 100644<br>index 00000000..fca0aaee<br>--- /dev/null<br>+++ b/cmake/FindLibUnwind.cmake<br>@@ -0,0 +1,87 @@<br>+#[========================================================================[.rst:<br>+FindLibUnwind<br>+--------<br>+Finds the libunwind library.<br>+<br>+Result Variables<br>+^^^^^^^^^^^^^^^^<br>+``LIBUNWIND_FOUND``<br>+ True if the system has the libunwind library.<br>+``LIBUNWIND_VERSION``<br>+ The version of the libunwind library which was found.<br>+``LIBUNWIND_INCLUDE_DIR``<br>+ Include directory needed to use libunwind.<br>+``LIBUNWIND_LIBRARIES``<br>+ Libraries needed to link to libunwind.<br>+<br>+Cache Variables<br>+^^^^^^^^^^^^^^^<br>+``LIBUNWIND_INCLUDE_DIR``<br>+ The directory containing ``libunwind.h``.<br>+``LIBUNWIND_LIBRARIES``<br>+ The paths to the libunwind libraries.<br>+#]========================================================================]<br>+<br>+include(FindPackageHandleStandardArgs)<br>+include(GetLibUnwindVersion)<br>+<br>+find_package(PkgConfig QUIET)<br>+pkg_check_modules(PC_LIBUNWIND QUIET libunwind)<br>+<br>+find_path(LIBUNWIND_INCLUDE_DIR libunwind.h ${PC_LIBUNWIND_INCLUDE_DIRS})<br>+if(LIBUNWIND_INCLUDE_DIR)<br>+ include_directories(${LIBUNWIND_INCLUDE_DIR})<br>+endif()<br>+<br>+if(BUILD_STATIC AND NOT APPLE)<br>+ set(LIBUNWIND_LIBRARY_NAME libunwind.a)<br>+else()<br>+ # Only a dynamic version of libunwind is available on macOS:<br>+ # also, we should link against the umbrella framework<br>+ # `System` - otherwise `ld` will complain that it cannot<br>+ # link directly with libunwind.tbd.<br>+ set(LIBUNWIND_LIBRARY_NAME System unwind)<br>+endif()<br>+find_library(LIBUNWIND_LIBRARY NAMES ${LIBUNWIND_LIBRARY_NAME}<br>+ PATHS ${PC_LIBUNWIND_LIBRARY_DIRS})<br>+<br>+if(APPLE)<br>+ set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARY})<br>+else()<br>+ if(BUILD_STATIC)<br>+ set(LIBUNWIND_PLATFORM_LIBRARY_NAME<br>+ "libunwind-${CMAKE_SYSTEM_PROCESSOR}.a")<br>+ else()<br>+ set(LIBUNWIND_PLATFORM_LIBRARY_NAME<br>+ "unwind-${CMAKE_SYSTEM_PROCESSOR}")<br>+ endif()<br>+ find_library(LIBUNWIND_PLATFORM_LIBRARY ${LIBUNWIND_PLATFORM_LIBRARY_NAME}<br>+ ${PC_LIBUNWIND_LIBRARY_DIRS})<br>+ set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARY} ${LIBUNWIND_PLATFORM_LIBRARY})<br>+endif()<br>+<br>+if(BUILD_STATIC)<br>+ # libunwind could have been built with liblzma dependency:<br>+ # <a href="https://github.com/libunwind/libunwind/blob/4feb1152d1c4aaafbb2d504dbe34c6db5b6fe9f2/configure.ac#L302-L317" target="_blank">https://github.com/libunwind/libunwind/blob/4feb1152d1c4aaafbb2d504dbe34c6db5b6fe9f2/configure.ac#L302-L317</a><br>+ pkg_check_modules(PC_LIBLZMA QUIET liblzma)<br>+ find_library(LIBLZMA_LIBRARY liblzma.a ${PC_LIBLZMA_LIBRARY_DIRS})<br>+ if(NOT LIBLZMA_LIBRARY STREQUAL "LIBLZMA_LIBRARY-NOTFOUND")<br>+ message(STATUS "liblzma found")<br>+ set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARIES} ${LIBLZMA_LIBRARY})<br>+ endif()<br>+ # Ditto,<br>+ # <a href="https://github.com/libunwind/libunwind/blob/4feb1152d1c4aaafbb2d504dbe34c6db5b6fe9f2/configure.ac#L319-L334" target="_blank">https://github.com/libunwind/libunwind/blob/4feb1152d1c4aaafbb2d504dbe34c6db5b6fe9f2/configure.ac#L319-L334</a><br>+ set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARIES} ZLIB::ZLIB)<br>+endif()<br>+<br>+if(PC_LIBUNWIND_VERSION)<br>+ set(LIBUNWIND_VERSION ${PC_LIBUNWIND_VERSION})<br>+else()<br>+ GetLibUnwindVersion(LIBUNWIND_VERSION)<br>+endif()<br>+<br>+find_package_handle_standard_args(LibUnwind<br>+ VERSION_VAR LIBUNWIND_VERSION<br>+ REQUIRED_VARS LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES)<br>+<br>+mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES)<br>diff --git a/cmake/GetLibUnwindVersion.cmake b/cmake/GetLibUnwindVersion.cmake<br>new file mode 100644<br>index 00000000..af833478<br>--- /dev/null<br>+++ b/cmake/GetLibUnwindVersion.cmake<br>@@ -0,0 +1,12 @@<br>+function(GetLibUnwindVersion _LIBUNWIND_VERSION)<br>+ set(_LIBUNWIND_VERSION_HEADER "${LIBUNWIND_INCLUDE_DIR}/libunwind-common.h")<br>+ if(LIBUNWIND_LIBRARY AND EXISTS ${_LIBUNWIND_VERSION_HEADER})<br>+ file(READ ${_LIBUNWIND_VERSION_HEADER}<br>+ _LIBUNWIND_VERSION_HEADER_CONTENTS)<br>+ string(REGEX MATCH<br>+ "#define UNW_VERSION_MAJOR[ \t]+([0-9]+)\n#define UNW_VERSION_MINOR[ \t]+([0-9]+)"<br>+ _VERSION_REGEX "${_LIBUNWIND_VERSION_HEADER_CONTENTS}")<br>+ set(${_LIBUNWIND_VERSION} "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}"<br>+ PARENT_SCOPE)<br>+ endif()<br>+endfunction()<br>diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt<br>index dffc0a4d..50768236 100644<br>--- a/src/CMakeLists.txt<br>+++ b/src/CMakeLists.txt<br>@@ -283,6 +283,10 @@ add_dependencies(core_shared buildvm_output)<br> <br> list(APPEND TARGET_LIBS m)<br> <br>+if(NOT LUAJIT_DISABLE_SYSPROF)<br>+ list(APPEND TARGET_LIBS ${LIBUNWIND_LIBRARIES})<br>+endif()<br>+<br> set(LIB_OBJECTS_STATIC<br>   $<TARGET_OBJECTS:vm_static><br>   $<TARGET_OBJECTS:core_static><br>diff --git a/src/Makefile.original b/src/Makefile.original<br>index 593b310d..3c3ae7f2 100644<br>--- a/src/Makefile.original<br>+++ b/src/Makefile.original<br>@@ -289,6 +289,16 @@ ifneq (,$(findstring LJ_TARGET_PS3 1,$(TARGET_TESTARCH)))<br>   TARGET_XLIBS+= -lpthread<br> endif<br> <br>+ifneq (,$(findstring LJ_HASSYSPROF ,$(TARGET_TESTARCH)))<br>+ HAS_LIBUNWIND=$(shell $(TARGET_LD) -lunwind -lunwind-x86_64 -c 2>/dev/null; echo $$?)<br>+ifneq (,$(HAS_LIBUNWIND))<br>+ TARGET_XCFLAGS+= -DLUAJIT_DISABLE_SYSPROF<br>+else<br>+ TARGET_XLIBS+= -lunwind -lunwind-x86_64<br>+ TARGET_XCFLAGS+= -fno-omit-frame-pointer -fasynchronous-unwind-tables<br>+endif<br>+endif<br>+<br> TARGET_XCFLAGS+= $(CCOPT_$(TARGET_LJARCH))<br> TARGET_ARCH+= $(patsubst %,-DLUAJIT_TARGET=LUAJIT_ARCH_%,$(TARGET_LJARCH))<br> <br>diff --git a/src/lj_sysprof.c b/src/lj_sysprof.c<br>index 2e9ed9b3..4ccb03e8 100644<br>--- a/src/lj_sysprof.c<br>+++ b/src/lj_sysprof.c<br>@@ -26,7 +26,15 @@<br> <br> #include <pthread.h><br> #include <errno.h><br>-#include <execinfo.h><br>+<br>+/*<br>+** We only need local unwinding, then a special implementation<br>+** can be selected which may run much faster than the generic<br>+** implementation which supports both kinds of unwinding, local<br>+** and remote.<br>+*/<br>+#define UNW_LOCAL_ONLY<br>+#include <libunwind.h><br> <br> /*<br> ** Number of profiler frames we need to omit during stack<br>@@ -85,6 +93,34 @@ static struct sysprof sysprof = {0};<br> <br> /* --- Stream ------------------------------------------------------------- */<br> <br>+static ssize_t collect_stack(void **buffer, int size)<br>+{<br>+ int frame_no = 0;<br>+ unw_context_t unw_ctx;<br>+ unw_cursor_t unw_cur;<br>+<br>+ int rc = unw_getcontext(&unw_ctx);<br>+ if (rc != 0)<br>+ return -1;<br>+<br>+ rc = unw_init_local(&unw_cur, &unw_ctx);<br>+ if (rc != 0)<br>+ return -1;<br>+<br>+ for (; frame_no < size; ++frame_no) {<br>+ unw_word_t ip;<br>+ rc = unw_get_reg(&unw_cur, UNW_REG_IP, &ip);<br>+ if (rc != 0)<br>+ return -1;<br>+<br>+ buffer[frame_no] = (void *)ip;<br>+ rc = unw_step(&unw_cur);<br>+ if (rc <= 0)<br>+ break;<br>+ }<br>+ return frame_no;<br>+}<br>+<br> static const uint8_t ljp_header[] = {'l', 'j', 'p', LJP_FORMAT_VERSION,<br>                                       0x0, 0x0, 0x0};<br> <br>@@ -197,10 +233,11 @@ static void default_backtrace_host(void *(writer)(int frame_no, void *addr))<br>   int max_depth = sp->opt.mode == LUAM_SYSPROF_LEAF<br>                   ? SYSPROF_HANDLER_STACK_DEPTH + 1<br>                   : SYSPROF_BACKTRACE_FRAME_MAX;<br>- const int depth = backtrace(backtrace_buf, max_depth);<br>+ const int depth = collect_stack(backtrace_buf, max_depth);<br>   int level;<br> <br>   lua_assert(depth <= max_depth);<br>+ lua_assert(depth != -1);<br>   for (level = SYSPROF_HANDLER_STACK_DEPTH; level < depth; ++level) {<br>     if (!writer(level - SYSPROF_HANDLER_STACK_DEPTH + 1, backtrace_buf[level]))<br>       return;<br>@@ -410,20 +447,12 @@ int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {<br> <br>   if (sp->state != SPS_IDLE)<br>     return PROFILE_ERRUSE;<br>- if (backtracer == NULL) {<br>+<br>+ if (backtracer == NULL)<br>     sp->backtracer = default_backtrace_host;<br>- /*<br>- ** XXX: `backtrace` is not signal-safe, according to man,<br>- ** because it is lazy loaded on the first call, which triggers<br>- ** allocations. We need to call `backtrace` before starting profiling<br>- ** to avoid lazy loading.<br>- */<br>- void *dummy = NULL;<br>- backtrace(&dummy, 1);<br>- }<br>- else {<br>+ else<br>     sp->backtracer = backtracer;<br>- }<br>+<br>   if (!is_unconfigured(sp)) {<br>     sp->state = SPS_IDLE;<br>   }<br>diff --git a/test/tarantool-tests/CMakeLists.txt b/test/tarantool-tests/CMakeLists.txt<br>index a428d009..af284300 100644<br>--- a/test/tarantool-tests/CMakeLists.txt<br>+++ b/test/tarantool-tests/CMakeLists.txt<br>@@ -94,6 +94,12 @@ set(LUA_TEST_ENV<br>   "LUA_CPATH=\"${LUA_CPATH}\""<br> )<br> <br>+if(LUAJIT_DISABLE_SYSPROF)<br>+ string(CONCAT LUA_EXCLUDE_TESTS [[\{\"misclib-sysprof-lapi\",]]<br>+ [[\"gh-7264-add-proto-trace-sysprof-default\",]]<br>+ [[\"misclib-sysprof-capi\"\}]])<br>+endif()<br>+<br> if(CMAKE_VERBOSE_MAKEFILE)<br>   list(APPEND LUA_TEST_FLAGS --verbose)<br> endif()<br>@@ -146,6 +152,7 @@ add_custom_command(TARGET tarantool-tests<br>       --ext ${LUA_TEST_SUFFIX}<br>       --jobs ${CMAKE_BUILD_PARALLEL_LEVEL}<br>       ${LUA_TEST_FLAGS}<br>+ :: --exclude=${LUA_EXCLUDE_TESTS}<br>   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}<br> )<br> <br>diff --git a/test/tarantool-tests/gh-7264-add-proto-trace-sysprof-default.test.lua b/test/tarantool-tests/gh-7264-add-proto-trace-sysprof-default.test.lua<br>index 15bd0a8b..424a6454 100644<br>--- a/test/tarantool-tests/gh-7264-add-proto-trace-sysprof-default.test.lua<br>+++ b/test/tarantool-tests/gh-7264-add-proto-trace-sysprof-default.test.lua<br>@@ -1,7 +1,8 @@<br> -- Sysprof is implemented for x86 and x64 architectures only.<br>-require('utils').skipcond(<br>+local utils = require('utils')<br>+utils.skipcond(<br>   jit.arch ~= 'x86' and jit.arch ~= 'x64' or jit.os ~= 'Linux'<br>- or require('ffi').abi('gc64'),<br>+ or require('ffi').abi('gc64') or utils.is_excluded(arg),<br>   jit.arch..' architecture or '..jit.os..<br>   ' OS is NIY for sysprof'<br> )<br>diff --git a/test/tarantool-tests/lj-603-err-snap-restore.test.lua b/test/tarantool-tests/lj-603-err-snap-restore.test.lua<br>index b5353e85..8e8d7db5 100644<br>--- a/test/tarantool-tests/lj-603-err-snap-restore.test.lua<br>+++ b/test/tarantool-tests/lj-603-err-snap-restore.test.lua<br>@@ -15,7 +15,7 @@ test:plan(2)<br> -- error handling"), etc.).<br> -- This amount is suited well for GC64 and non-GC64 mode.<br> -- luacheck: no unused<br>-local _, _, _, _, _, _<br>+local _, _, _, _, _<br> <br> local handler_is_called = false<br> local recursive_f<br>diff --git a/test/tarantool-tests/misclib-sysprof-capi.test.lua b/test/tarantool-tests/misclib-sysprof-capi.test.lua<br>index dad0fe4a..0b669503 100644<br>--- a/test/tarantool-tests/misclib-sysprof-capi.test.lua<br>+++ b/test/tarantool-tests/misclib-sysprof-capi.test.lua<br>@@ -1,9 +1,12 @@<br> -- Sysprof is implemented for x86 and x64 architectures only.<br> local utils = require("utils")<br>+local ffi = require("ffi")<br>+-- luacheck: globals is_excluded<br> utils.skipcond(<br>- jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux",<br>+ jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux"<br>+ or ffi.abi("gc64") or utils.is_excluded(arg),<br>   jit.arch.." architecture or "..jit.os..<br>- " OS is NIY for sysprof"<br>+ " OS is NIY for sysprof, or the test suite was excluded"<br> )<br> <br> local testsysprof = require("testsysprof")<br>@@ -14,15 +17,11 @@ local jit = require('jit')<br> jit.off()<br> <br> local test = tap.test("clib-misc-sysprof")<br>-test:plan(2)<br>+test:plan(4)<br> <br> test:ok(testsysprof.base())<br> test:ok(testsysprof.validation())<br> <br>--- FIXME: The following two tests are disabled because sometimes<br>--- `backtrace` dynamically loads a platform-specific unwinder, which is<br>--- not signal-safe.<br>---[[<br> local function lua_payload(n)<br>   if n <= 1 then<br>     return n<br>@@ -55,5 +54,4 @@ jit.on()<br> jit.flush()<br> <br> test:ok(testsysprof.profile_func(payload))<br>---]]<br> os.exit(test:check() and 0 or 1)<br>diff --git a/test/tarantool-tests/misclib-sysprof-lapi.test.lua b/test/tarantool-tests/misclib-sysprof-lapi.test.lua<br>index 4bf10e8d..b1c5a377 100644<br>--- a/test/tarantool-tests/misclib-sysprof-lapi.test.lua<br>+++ b/test/tarantool-tests/misclib-sysprof-lapi.test.lua<br>@@ -1,9 +1,12 @@<br> -- Sysprof is implemented for x86 and x64 architectures only.<br> local utils = require("utils")<br>+local ffi = require("ffi")<br>+-- luacheck: globals is_excluded<br> utils.skipcond(<br>- jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux",<br>+ jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux"<br>+ or ffi.abi("gc64") or utils.is_excluded(arg),<br>   jit.arch.." architecture or "..jit.os..<br>- " OS is NIY for sysprof"<br>+ " OS is NIY for sysprof, or the test suite was excluded"<br> )<br> <br> local tap = require("tap")<br>diff --git a/test/tarantool-tests/utils.lua b/test/tarantool-tests/utils.lua<br>index eb11d40d..bb6f1aa5 100644<br>--- a/test/tarantool-tests/utils.lua<br>+++ b/test/tarantool-tests/utils.lua<br>@@ -135,6 +135,45 @@ function M.profilename(name)<br>   return (arg[0]:gsub('^(.+)/([^/]+)%.test%.lua$', replacepattern))<br> end<br> <br>+-- XXX: Some tests need more complicated skipconds that can be<br>+-- implemented in Lua, so this function checks if the test was<br>+-- marked as excluded via the CLI arg.<br>+function M.is_excluded(arg)<br>+ if #arg == 0 then<br>+ return false<br>+ end<br>+<br>+ local exclusions = nil<br>+ for i = 1, #arg do<br>+ local excl_arg = string.match(arg[i], '--exclude=({.+})')<br>+<br>+ if excl_arg == nil then<br>+ break<br>+ end<br>+<br>+ assert(exclusions == nil, '--exclude was already provided')<br>+<br>+ local excl_f, err = loadstring('return ' .. excl_arg)<br>+ assert(excl_f, err)<br>+<br>+ local excl = excl_f()<br>+ assert(type(excl) == 'table', '--exclude option must provide a valid array')<br>+ exclusions = excl<br>+ end<br>+<br>+ if exclusions == nil then<br>+ return false<br>+ end<br>+<br>+ local basename = string.match(arg[0], '[%w%-]+%.test%.lua')<br>+ for _, name in ipairs(exclusions) do<br>+ if basename == name .. '.test.lua' then<br>+ return true<br>+ end<br>+ end<br>+ return false<br>+end<br>+<br> M.const = {<br>   -- XXX: Max nins is limited by max IRRef, that equals to<br>   -- REF_DROP - REF_BIAS. Unfortunately, these constants are not<br>--<br>2.38.1</div></div></div></div></blockquote><div> </div></BODY></HTML>