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 708BC152E20; Tue, 6 Dec 2022 09:47:18 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 708BC152E20 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1670309238; bh=NUlVYbTF/gD6wTLK9cG56BUr0w02o4X/QTa5FRKLjgA=; h=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=hFC7q922f0B6Omu18vufMRwDEEC7YC4qxZrJEaW0YJWhjanmmmJjikFb5jVcFHIVB u5O4u0nO5Z1/yKsd5EsvAYBPTYVFLMi/zd651/N6wHqu9e01q3BB3yF80nzgXicja5 FDbp9R0DYz9DxCcVCI92kOujf7gTou8UbvWyZct4= Received: from mail-lf1-f42.google.com (mail-lf1-f42.google.com [209.85.167.42]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 76A567036F for ; Tue, 6 Dec 2022 09:47:17 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 76A567036F Received: by mail-lf1-f42.google.com with SMTP id d6so22163287lfs.10 for ; Mon, 05 Dec 2022 22:47:17 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=7mmLoF4pg2hZc3PrID2ynfNv/UOJ8r2Y8XtFzekfrKg=; b=CgnxReVK7XZLVFt/1HmkEkFGUE7AwLYVfhi4da4U6s1WnhxpntVn1Ju8b5lGhRcnd+ GyxktJZ5z4UT+2X6DKFoxD4q38YzY2j1uOlNxit29uHsdSS4KZT+px9tyM5hR5MLJrj2 JBFZpahW/Op+TfUavMRN0+4TOwPnP1sr9BMlE/DChDk+/OQUvID6PWeT2yK1vNpI4GqH RcEN3WYcvnUrVU0CujKS+FsxEU03ZEzk7h8uBfShpwXEmqIM6IzhloUPW/cNcOSkMyec AM5sFIAz9if4XwnmW9kMpuTPpRRfboQzZhoK8S3DIpDwXzPxioMDWtTGCAus6NC0PdTN 0yTA== X-Gm-Message-State: ANoB5pmNpzUja+SSmUB9HZlOAM59Ak59XcBmV2DXKNQr0Y0pbPbCM5SW g0lQP5cWLlLp4QKxCNs1O8pLbloSZznvSg== X-Google-Smtp-Source: AA0mqf4C42UVaTBmKbNBIzU826/Qf4bQrwHXRe/WHiKVzirrErlSGxazsjbT6uNHFDXRjqEUCQ9qww== X-Received: by 2002:a19:6558:0:b0:4ac:fbf2:12ab with SMTP id c24-20020a196558000000b004acfbf212abmr27721635lfj.384.1670309236143; Mon, 05 Dec 2022 22:47:16 -0800 (PST) Received: from localhost.localdomain (89-179-104-69.broadband.corbina.ru. [89.179.104.69]) by smtp.gmail.com with ESMTPSA id b2-20020a05651c032200b00279a6b9a7efsm1340727ljp.83.2022.12.05.22.47.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Dec 2022 22:47:15 -0800 (PST) X-Google-Original-From: Maxim Kokryashkin To: tarantool-patches@dev.tarantool.org, sergos@tarantool.org, skaplun@tarantool.org Date: Tue, 6 Dec 2022 09:47:12 +0300 Message-Id: <20221206064712.755124-1-m.kokryashkin@tarantool.org> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH luajit v2] sysprof: replace `backtrace` with libunwind 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: Maxim Kokryashkin via Tarantool-patches Reply-To: Maxim Kokryashkin Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" `backtrace` fails to unwind the host stack in LuaJIT, since there are no frame pointers during the vm calls. Sometimes, those failures cause crashes. This commit replaces it with the libunwind-based unwinder, which makes use of additional runtime info to provide robust unwinding without any frame pointers. Also, this commit enables C API tests, which used to crash with `backtrace`. The `lj-603-err-snap-restore.test.lua` was updated to correspond with the new size of the `arg` table. Part of tarantool/tarantool#781 --- Changes in v2: - Fixed comments as per review by Sergey - Fixed build for Makefile.original - Moved `is_exluded` to `utils` module CMakeLists.txt | 48 ++++++++-- cmake/FindLibUnwind.cmake | 87 +++++++++++++++++++ cmake/GetLibUnwindVersion.cmake | 12 +++ src/CMakeLists.txt | 4 + src/Makefile.original | 10 +++ src/lj_sysprof.c | 57 +++++++++--- test/tarantool-tests/CMakeLists.txt | 7 ++ ...4-add-proto-trace-sysprof-default.test.lua | 5 +- .../lj-603-err-snap-restore.test.lua | 2 +- .../misclib-sysprof-capi.test.lua | 14 ++- .../misclib-sysprof-lapi.test.lua | 7 +- test/tarantool-tests/utils.lua | 39 +++++++++ 12 files changed, 259 insertions(+), 33 deletions(-) create mode 100644 cmake/FindLibUnwind.cmake create mode 100644 cmake/GetLibUnwindVersion.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c870cce2..2ac32465 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,12 +91,9 @@ if(CMAKE_LIBRARY_ARCHITECTURE) AppendFlags(TARGET_C_FLAGS -DLUA_MULTILIB='"lib/${CMAKE_LIBRARY_ARCHITECTURE}"') endif() -# Since the assembler part does NOT maintain a frame pointer, it's -# pointless to slow down the C part by not omitting it. Debugging, -# tracebacks and unwinding are not affected -- the assembler part -# has frame unwind information and GCC emits it where needed (x64) -# or with -g. -AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer -fno-stack-protector) +AppendFlags(CMAKE_C_FLAGS -fno-stack-protector) +# The '-fomit-frame-pointer` is set depending on sysprof +# and libunwind support. # Redefined to benefit from expanding macros in gdb. set(CMAKE_C_FLAGS_DEBUG "-g -ggdb3") @@ -195,6 +192,45 @@ endif() option(LUAJIT_DISABLE_SYSPROF "LuaJIT platform and Lua profiler support" OFF) if(LUAJIT_DISABLE_SYSPROF) AppendFlags(TARGET_C_FLAGS -DLUAJIT_DISABLE_SYSPROF) + AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer) +else() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND + ( + CMAKE_SYSTEM_PROCESSOR STREQUAL "i386" OR + CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" OR + CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" + ) + ) + # XXX: Libunwind can be provided externally. + if(NOT LIBUNWIND_LIBRARIES) + find_package(LibUnwind MODULE QUIET) + endif() + + if(NOT LIBUNWIND_FOUND AND NOT LIBUNWIND_LIBRARIES) + set(LUAJIT_DISABLE_SYSPROF ON) + AppendFlags(TARGET_C_FLAGS -DLUAJIT_DISABLE_SYSPROF) + + # Since the assembler part does NOT maintain a frame + # pointer, it's pointless to slow down the C part by not + # omitting it. Debugging, tracebacks and unwinding are not + # affected -- the assembler part has frame unwind + # information and GCC emits it where needed (x64) or + # with -g. + AppendFlags(CMAKE_C_FLAGS -fomit-frame-pointer) + message(STATUS "Libunwind was not found, sysprof is disabled") + + # XXX: CMake sets those variables globally, so using the + # `unset` here doesn't really clear them out of the parent + # scope. As stated in the `unset` documentation, to force + # a variable reference of the form ${VAR} to return an + # empty string, you need to use `set( "")`. + set(LIBUNWIND_INCLUDE_DIR "" PARENT_SCOPE) + set(LIBUNWIND_LIBRARIES "" PARENT_SCOPE) + set(LIBUNWIND_FOUND FALSE PARENT_SCOPE) + else() + AppendFlags(CMAKE_C_FLAGS -fno-omit-frame-pointer -fasynchronous-unwind-tables) + endif() + endif() endif() # Switch to harder (and slower) hash function when a collision diff --git a/cmake/FindLibUnwind.cmake b/cmake/FindLibUnwind.cmake new file mode 100644 index 00000000..fca0aaee --- /dev/null +++ b/cmake/FindLibUnwind.cmake @@ -0,0 +1,87 @@ +#[========================================================================[.rst: +FindLibUnwind +-------- +Finds the libunwind library. + +Result Variables +^^^^^^^^^^^^^^^^ +``LIBUNWIND_FOUND`` + True if the system has the libunwind library. +``LIBUNWIND_VERSION`` + The version of the libunwind library which was found. +``LIBUNWIND_INCLUDE_DIR`` + Include directory needed to use libunwind. +``LIBUNWIND_LIBRARIES`` + Libraries needed to link to libunwind. + +Cache Variables +^^^^^^^^^^^^^^^ +``LIBUNWIND_INCLUDE_DIR`` + The directory containing ``libunwind.h``. +``LIBUNWIND_LIBRARIES`` + The paths to the libunwind libraries. +#]========================================================================] + +include(FindPackageHandleStandardArgs) +include(GetLibUnwindVersion) + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_LIBUNWIND QUIET libunwind) + +find_path(LIBUNWIND_INCLUDE_DIR libunwind.h ${PC_LIBUNWIND_INCLUDE_DIRS}) +if(LIBUNWIND_INCLUDE_DIR) + include_directories(${LIBUNWIND_INCLUDE_DIR}) +endif() + +if(BUILD_STATIC AND NOT APPLE) + set(LIBUNWIND_LIBRARY_NAME libunwind.a) +else() + # Only a dynamic version of libunwind is available on macOS: + # also, we should link against the umbrella framework + # `System` - otherwise `ld` will complain that it cannot + # link directly with libunwind.tbd. + set(LIBUNWIND_LIBRARY_NAME System unwind) +endif() +find_library(LIBUNWIND_LIBRARY NAMES ${LIBUNWIND_LIBRARY_NAME} + PATHS ${PC_LIBUNWIND_LIBRARY_DIRS}) + +if(APPLE) + set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARY}) +else() + if(BUILD_STATIC) + set(LIBUNWIND_PLATFORM_LIBRARY_NAME + "libunwind-${CMAKE_SYSTEM_PROCESSOR}.a") + else() + set(LIBUNWIND_PLATFORM_LIBRARY_NAME + "unwind-${CMAKE_SYSTEM_PROCESSOR}") + endif() + find_library(LIBUNWIND_PLATFORM_LIBRARY ${LIBUNWIND_PLATFORM_LIBRARY_NAME} + ${PC_LIBUNWIND_LIBRARY_DIRS}) + set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARY} ${LIBUNWIND_PLATFORM_LIBRARY}) +endif() + +if(BUILD_STATIC) + # libunwind could have been built with liblzma dependency: + # https://github.com/libunwind/libunwind/blob/4feb1152d1c4aaafbb2d504dbe34c6db5b6fe9f2/configure.ac#L302-L317 + pkg_check_modules(PC_LIBLZMA QUIET liblzma) + find_library(LIBLZMA_LIBRARY liblzma.a ${PC_LIBLZMA_LIBRARY_DIRS}) + if(NOT LIBLZMA_LIBRARY STREQUAL "LIBLZMA_LIBRARY-NOTFOUND") + message(STATUS "liblzma found") + set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARIES} ${LIBLZMA_LIBRARY}) + endif() + # Ditto, + # https://github.com/libunwind/libunwind/blob/4feb1152d1c4aaafbb2d504dbe34c6db5b6fe9f2/configure.ac#L319-L334 + set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARIES} ZLIB::ZLIB) +endif() + +if(PC_LIBUNWIND_VERSION) + set(LIBUNWIND_VERSION ${PC_LIBUNWIND_VERSION}) +else() + GetLibUnwindVersion(LIBUNWIND_VERSION) +endif() + +find_package_handle_standard_args(LibUnwind + VERSION_VAR LIBUNWIND_VERSION + REQUIRED_VARS LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES) + +mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES) diff --git a/cmake/GetLibUnwindVersion.cmake b/cmake/GetLibUnwindVersion.cmake new file mode 100644 index 00000000..af833478 --- /dev/null +++ b/cmake/GetLibUnwindVersion.cmake @@ -0,0 +1,12 @@ +function(GetLibUnwindVersion _LIBUNWIND_VERSION) + set(_LIBUNWIND_VERSION_HEADER "${LIBUNWIND_INCLUDE_DIR}/libunwind-common.h") + if(LIBUNWIND_LIBRARY AND EXISTS ${_LIBUNWIND_VERSION_HEADER}) + file(READ ${_LIBUNWIND_VERSION_HEADER} + _LIBUNWIND_VERSION_HEADER_CONTENTS) + string(REGEX MATCH + "#define UNW_VERSION_MAJOR[ \t]+([0-9]+)\n#define UNW_VERSION_MINOR[ \t]+([0-9]+)" + _VERSION_REGEX "${_LIBUNWIND_VERSION_HEADER_CONTENTS}") + set(${_LIBUNWIND_VERSION} "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" + PARENT_SCOPE) + endif() +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dffc0a4d..50768236 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -283,6 +283,10 @@ add_dependencies(core_shared buildvm_output) list(APPEND TARGET_LIBS m) +if(NOT LUAJIT_DISABLE_SYSPROF) + list(APPEND TARGET_LIBS ${LIBUNWIND_LIBRARIES}) +endif() + set(LIB_OBJECTS_STATIC $ $ diff --git a/src/Makefile.original b/src/Makefile.original index 593b310d..3c3ae7f2 100644 --- a/src/Makefile.original +++ b/src/Makefile.original @@ -289,6 +289,16 @@ ifneq (,$(findstring LJ_TARGET_PS3 1,$(TARGET_TESTARCH))) TARGET_XLIBS+= -lpthread endif +ifneq (,$(findstring LJ_HASSYSPROF ,$(TARGET_TESTARCH))) + HAS_LIBUNWIND=$(shell $(TARGET_LD) -lunwind -lunwind-x86_64 -c 2>/dev/null; echo $$?) +ifneq (,$(HAS_LIBUNWIND)) + TARGET_XCFLAGS+= -DLUAJIT_DISABLE_SYSPROF +else + TARGET_XLIBS+= -lunwind -lunwind-x86_64 + TARGET_XCFLAGS+= -fno-omit-frame-pointer -fasynchronous-unwind-tables +endif +endif + TARGET_XCFLAGS+= $(CCOPT_$(TARGET_LJARCH)) TARGET_ARCH+= $(patsubst %,-DLUAJIT_TARGET=LUAJIT_ARCH_%,$(TARGET_LJARCH)) diff --git a/src/lj_sysprof.c b/src/lj_sysprof.c index 2e9ed9b3..4ccb03e8 100644 --- a/src/lj_sysprof.c +++ b/src/lj_sysprof.c @@ -26,7 +26,15 @@ #include #include -#include + +/* +** We only need local unwinding, then a special implementation +** can be selected which may run much faster than the generic +** implementation which supports both kinds of unwinding, local +** and remote. +*/ +#define UNW_LOCAL_ONLY +#include /* ** Number of profiler frames we need to omit during stack @@ -85,6 +93,34 @@ static struct sysprof sysprof = {0}; /* --- Stream ------------------------------------------------------------- */ +static ssize_t collect_stack(void **buffer, int size) +{ + int frame_no = 0; + unw_context_t unw_ctx; + unw_cursor_t unw_cur; + + int rc = unw_getcontext(&unw_ctx); + if (rc != 0) + return -1; + + rc = unw_init_local(&unw_cur, &unw_ctx); + if (rc != 0) + return -1; + + for (; frame_no < size; ++frame_no) { + unw_word_t ip; + rc = unw_get_reg(&unw_cur, UNW_REG_IP, &ip); + if (rc != 0) + return -1; + + buffer[frame_no] = (void *)ip; + rc = unw_step(&unw_cur); + if (rc <= 0) + break; + } + return frame_no; +} + static const uint8_t ljp_header[] = {'l', 'j', 'p', LJP_FORMAT_VERSION, 0x0, 0x0, 0x0}; @@ -197,10 +233,11 @@ static void default_backtrace_host(void *(writer)(int frame_no, void *addr)) int max_depth = sp->opt.mode == LUAM_SYSPROF_LEAF ? SYSPROF_HANDLER_STACK_DEPTH + 1 : SYSPROF_BACKTRACE_FRAME_MAX; - const int depth = backtrace(backtrace_buf, max_depth); + const int depth = collect_stack(backtrace_buf, max_depth); int level; lua_assert(depth <= max_depth); + lua_assert(depth != -1); for (level = SYSPROF_HANDLER_STACK_DEPTH; level < depth; ++level) { if (!writer(level - SYSPROF_HANDLER_STACK_DEPTH + 1, backtrace_buf[level])) return; @@ -410,20 +447,12 @@ int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) { if (sp->state != SPS_IDLE) return PROFILE_ERRUSE; - if (backtracer == NULL) { + + if (backtracer == NULL) sp->backtracer = default_backtrace_host; - /* - ** XXX: `backtrace` is not signal-safe, according to man, - ** because it is lazy loaded on the first call, which triggers - ** allocations. We need to call `backtrace` before starting profiling - ** to avoid lazy loading. - */ - void *dummy = NULL; - backtrace(&dummy, 1); - } - else { + else sp->backtracer = backtracer; - } + if (!is_unconfigured(sp)) { sp->state = SPS_IDLE; } diff --git a/test/tarantool-tests/CMakeLists.txt b/test/tarantool-tests/CMakeLists.txt index a428d009..af284300 100644 --- a/test/tarantool-tests/CMakeLists.txt +++ b/test/tarantool-tests/CMakeLists.txt @@ -94,6 +94,12 @@ set(LUA_TEST_ENV "LUA_CPATH=\"${LUA_CPATH}\"" ) +if(LUAJIT_DISABLE_SYSPROF) + string(CONCAT LUA_EXCLUDE_TESTS [[\{\"misclib-sysprof-lapi\",]] + [[\"gh-7264-add-proto-trace-sysprof-default\",]] + [[\"misclib-sysprof-capi\"\}]]) +endif() + if(CMAKE_VERBOSE_MAKEFILE) list(APPEND LUA_TEST_FLAGS --verbose) endif() @@ -146,6 +152,7 @@ add_custom_command(TARGET tarantool-tests --ext ${LUA_TEST_SUFFIX} --jobs ${CMAKE_BUILD_PARALLEL_LEVEL} ${LUA_TEST_FLAGS} + :: --exclude=${LUA_EXCLUDE_TESTS} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) 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 index 15bd0a8b..424a6454 100644 --- 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 @@ -1,7 +1,8 @@ -- Sysprof is implemented for x86 and x64 architectures only. -require('utils').skipcond( +local utils = require('utils') +utils.skipcond( jit.arch ~= 'x86' and jit.arch ~= 'x64' or jit.os ~= 'Linux' - or require('ffi').abi('gc64'), + or require('ffi').abi('gc64') or utils.is_excluded(arg), jit.arch..' architecture or '..jit.os.. ' OS is NIY for sysprof' ) diff --git a/test/tarantool-tests/lj-603-err-snap-restore.test.lua b/test/tarantool-tests/lj-603-err-snap-restore.test.lua index b5353e85..8e8d7db5 100644 --- a/test/tarantool-tests/lj-603-err-snap-restore.test.lua +++ b/test/tarantool-tests/lj-603-err-snap-restore.test.lua @@ -15,7 +15,7 @@ test:plan(2) -- error handling"), etc.). -- This amount is suited well for GC64 and non-GC64 mode. -- luacheck: no unused -local _, _, _, _, _, _ +local _, _, _, _, _ local handler_is_called = false local recursive_f diff --git a/test/tarantool-tests/misclib-sysprof-capi.test.lua b/test/tarantool-tests/misclib-sysprof-capi.test.lua index dad0fe4a..0b669503 100644 --- a/test/tarantool-tests/misclib-sysprof-capi.test.lua +++ b/test/tarantool-tests/misclib-sysprof-capi.test.lua @@ -1,9 +1,12 @@ -- Sysprof is implemented for x86 and x64 architectures only. local utils = require("utils") +local ffi = require("ffi") +-- luacheck: globals is_excluded utils.skipcond( - jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux", + jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux" + or ffi.abi("gc64") or utils.is_excluded(arg), jit.arch.." architecture or "..jit.os.. - " OS is NIY for sysprof" + " OS is NIY for sysprof, or the test suite was excluded" ) local testsysprof = require("testsysprof") @@ -14,15 +17,11 @@ local jit = require('jit') jit.off() local test = tap.test("clib-misc-sysprof") -test:plan(2) +test:plan(4) test:ok(testsysprof.base()) test:ok(testsysprof.validation()) --- FIXME: The following two tests are disabled because sometimes --- `backtrace` dynamically loads a platform-specific unwinder, which is --- not signal-safe. ---[[ local function lua_payload(n) if n <= 1 then return n @@ -55,5 +54,4 @@ jit.on() jit.flush() test:ok(testsysprof.profile_func(payload)) ---]] os.exit(test:check() and 0 or 1) diff --git a/test/tarantool-tests/misclib-sysprof-lapi.test.lua b/test/tarantool-tests/misclib-sysprof-lapi.test.lua index 4bf10e8d..b1c5a377 100644 --- a/test/tarantool-tests/misclib-sysprof-lapi.test.lua +++ b/test/tarantool-tests/misclib-sysprof-lapi.test.lua @@ -1,9 +1,12 @@ -- Sysprof is implemented for x86 and x64 architectures only. local utils = require("utils") +local ffi = require("ffi") +-- luacheck: globals is_excluded utils.skipcond( - jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux", + jit.arch ~= "x86" and jit.arch ~= "x64" or jit.os ~= "Linux" + or ffi.abi("gc64") or utils.is_excluded(arg), jit.arch.." architecture or "..jit.os.. - " OS is NIY for sysprof" + " OS is NIY for sysprof, or the test suite was excluded" ) local tap = require("tap") diff --git a/test/tarantool-tests/utils.lua b/test/tarantool-tests/utils.lua index eb11d40d..bb6f1aa5 100644 --- a/test/tarantool-tests/utils.lua +++ b/test/tarantool-tests/utils.lua @@ -135,6 +135,45 @@ function M.profilename(name) return (arg[0]:gsub('^(.+)/([^/]+)%.test%.lua$', replacepattern)) end +-- XXX: Some tests need more complicated skipconds that can be +-- implemented in Lua, so this function checks if the test was +-- marked as excluded via the CLI arg. +function M.is_excluded(arg) + if #arg == 0 then + return false + end + + local exclusions = nil + for i = 1, #arg do + local excl_arg = string.match(arg[i], '--exclude=({.+})') + + if excl_arg == nil then + break + end + + assert(exclusions == nil, '--exclude was already provided') + + local excl_f, err = loadstring('return ' .. excl_arg) + assert(excl_f, err) + + local excl = excl_f() + assert(type(excl) == 'table', '--exclude option must provide a valid array') + exclusions = excl + end + + if exclusions == nil then + return false + end + + local basename = string.match(arg[0], '[%w%-]+%.test%.lua') + for _, name in ipairs(exclusions) do + if basename == name .. '.test.lua' then + return true + end + end + return false +end + M.const = { -- XXX: Max nins is limited by max IRRef, that equals to -- REF_DROP - REF_BIAS. Unfortunately, these constants are not -- 2.38.1