[Tarantool-patches] [PATCH v2 luajit 4/6] test: rewrite misclib-getmetrics-capi test in C

Sergey Bronnikov sergeyb at tarantool.org
Mon May 29 19:15:18 MSK 2023


Hi, Sergey

see my comments below

On 5/18/23 23:44, Sergey Kaplun wrote:
> This patch rewrites the aforementioned test with the usage libtest,
> recently introduced. Since we still stand in need of a Lua helper script
> for generation of traces, the original test file is reworked as a
> standalone script, which returns the table with helper functions. Each
> helper function is named the same as the test where it will be used. Now
> single quotes are used according to our Lua code style.
>
> In C part all asserts from glibc are replaced with the corresponding
> assert_{cond} from the libtest. Now tests return `TEST_EXIT_SUCCESS` at
> the finish. Also, the stack check for the amount of return results from
> the helper function is slightly changed, since there is one more stack
> slot in use (table with these functions). `snap_restores()` C function
> duplicates 4 times for each subtest. Common helper
> `check_snap_restores()` is used for each of them. Each error throwing is
> replaced with `bail_out()` call.
>
> NB: `lua_pop()` to clear the Lua stack after a call should be done before
> any possible assertion, which would exit from the test leaving the stack
> uncleaned.
>
> All skipconds use macros defined in <lj_arch.h>, so it is included in
> the test. As far as this test initializes the LuaJIT VM manually, there
> is no need to check `jit.status()` result; checking `LJ_HASJIT` is
> enough. Now, only JIT-related tests are skipped, when compiled without
> JIT. Nevertheless, all tests are skipped for *BSD arches.
>
> Also, this patch sets the new CMake variable named `LUAJIT_LIBRARY`
> equal to `LUAJIT_LIB` in `PARENT_SCOPE` to be used in tarantool-c-tests
> linking.
>
> Also, .c_test suffix is added to the <.gitignore>.
>
> Part of tarantool/tarantool#7900
> ---
>   .gitignore                                    |   1 +
>   src/CMakeLists.txt                            |   2 +
>   test/tarantool-c-tests/CMakeLists.txt         |  32 +-
>   .../misclib-getmetrics-capi-script.lua}       |  83 ++---
>   .../misclib-getmetrics-capi.test.c            | 343 ++++++++++++++++++
>   test/tarantool-tests/CMakeLists.txt           |   1 -
>   .../misclib-getmetrics-capi/CMakeLists.txt    |   1 -
>   .../misclib-getmetrics-capi/testgetmetrics.c  | 270 --------------
>   8 files changed, 412 insertions(+), 321 deletions(-)
>   rename test/{tarantool-tests/misclib-getmetrics-capi.test.lua => tarantool-c-tests/misclib-getmetrics-capi-script.lua} (68%)
>   create mode 100644 test/tarantool-c-tests/misclib-getmetrics-capi.test.c
>   delete mode 100644 test/tarantool-tests/misclib-getmetrics-capi/CMakeLists.txt
>   delete mode 100644 test/tarantool-tests/misclib-getmetrics-capi/testgetmetrics.c
>
> diff --git a/.gitignore b/.gitignore
> index b7908aee..dc5ea5fc 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -24,3 +24,4 @@ install_manifest.txt
>   luajit-parse-memprof
>   luajit-parse-sysprof
>   luajit.pc
> +*.c_test
> diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
> index dffc0a4d..fed4c38d 100644
> --- a/src/CMakeLists.txt
> +++ b/src/CMakeLists.txt
> @@ -325,6 +325,8 @@ if(NOT BUILDMODE STREQUAL "dynamic")
>     set(LUAJIT_BIN luajit_static)
>     set(LUAJIT_LIB libluajit_static)
>   endif()
> +# Need for the test linking, so the PARENT_SCOPE option is used.
> +set(LUAJIT_LIBRARY ${LUAJIT_LIB} PARENT_SCOPE)
>   set(LIBLUAJIT_DEPS ${LIBLUAJIT_STATIC_DEPS} ${LIBLUAJIT_SHARED_DEPS})
>   
>   add_executable(${LUAJIT_BIN} EXCLUDE_FROM_ALL ${CLI_SOURCES})
> diff --git a/test/tarantool-c-tests/CMakeLists.txt b/test/tarantool-c-tests/CMakeLists.txt
> index c6b7cd30..c9d75d6c 100644
> --- a/test/tarantool-c-tests/CMakeLists.txt
> +++ b/test/tarantool-c-tests/CMakeLists.txt
> @@ -22,13 +22,37 @@ set_target_properties(libtest PROPERTIES
>     LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
>   )
>   
> -# XXX: For now, just build libtest. The tests to be depended on
> -# will be added in the next commit.
> +# TARGET_C_FLAGS is required here to be sure that headers like
> +# lj_arch.h in compiled test are consistent with the LuaJIT library
> +# to link.
> +AppendFlags(TESTS_C_FLAGS ${TARGET_C_FLAGS})
> +
> +set(CTEST_SRC_SUFFIX ".test.c")
> +file(GLOB tests "${CMAKE_CURRENT_SOURCE_DIR}/*${CTEST_SRC_SUFFIX}")
> +foreach(test_source ${tests})
> +  string(REGEX REPLACE ".+/([^/]+)${CTEST_SRC_SUFFIX}" "\\1" exe ${test_source})

Please replace with get_filename_component [1]:

--- a/test/tarantool-c-tests/CMakeLists.txt
+++ b/test/tarantool-c-tests/CMakeLists.txt
@@ -31,7 +31,7 @@ set(CTEST_SRC_SUFFIX ".test.c")
  file(GLOB tests "${CMAKE_CURRENT_SOURCE_DIR}/*${CTEST_SRC_SUFFIX}")
  foreach(test_source ${tests})
    # Get test name without suffix. Needed to set OUTPUT_NAME.
-  string(REGEX REPLACE ".+/([^/]+)${CTEST_SRC_SUFFIX}" "\\1" exe 
${test_source})
+  get_filename_component(exe ${test_source} NAME_WE)
    add_executable(${exe} EXCLUDE_FROM_ALL ${test_source})
    target_include_directories(${exe} PRIVATE
      ${CMAKE_CURRENT_SOURCE_DIR}

1: https://cmake.org/cmake/help/latest/command/get_filename_component.html


> +  add_executable(${exe} EXCLUDE_FROM_ALL ${test_source})
> +  target_include_directories(${exe} PRIVATE
> +    ${CMAKE_CURRENT_SOURCE_DIR}
> +    ${LUAJIT_SOURCE_DIR}
> +  )
> +  set_target_properties(${exe} PROPERTIES
> +    # `__FILE__` macro may not represnt absolute path to the
Typo: represnt
> +    # source file, depening on cmake version or
Typo: depening
> +    # -fmacro-prefix-map flag value.
> +    # Use custom macro.
> +    COMPILE_FLAGS "${TESTS_C_FLAGS} -D__ABS_FILENAME__='\"${test_source}\"'"
> +    OUTPUT_NAME "${exe}${C_TEST_SUFFIX}"
> +    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
> +  )
> +  target_link_libraries(${exe} libtest ${LUAJIT_LIBRARY})
> +  LIST(APPEND TESTS_COMPILED ${exe})
> +endforeach()
> +
>   add_custom_target(tarantool-c-tests
> -  DEPENDS libluajit libtest
> +  DEPENDS libluajit libtest ${TESTS_COMPILED}
>   )
>   
> -# XXX: For now, run 0 tests. Just verify that libtest was built.
>   add_custom_command(TARGET tarantool-c-tests
>     COMMENT "Running Tarantool C tests"
>     COMMAND
> diff --git a/test/tarantool-tests/misclib-getmetrics-capi.test.lua b/test/tarantool-c-tests/misclib-getmetrics-capi-script.lua
> similarity index 68%
> rename from test/tarantool-tests/misclib-getmetrics-capi.test.lua
> rename to test/tarantool-c-tests/misclib-getmetrics-capi-script.lua
> index 654e5545..2f0ee5cf 100644
> --- a/test/tarantool-tests/misclib-getmetrics-capi.test.lua
> +++ b/test/tarantool-c-tests/misclib-getmetrics-capi-script.lua
> @@ -1,32 +1,26 @@
> -local tap = require('tap')
> -local test = tap.test("clib-misc-getmetrics"):skipcond({
> -  ['Test requires JIT enabled'] = not jit.status(),
> -  ['Disabled on *BSD due to #4819'] = jit.os == 'BSD',
> -})
> +local ffi = require('ffi')
>   
> -test:plan(11)
> +-- Auxiliary script to provide Lua functions to be used in tests
> +-- for `getmetrics()` C API inside the test
> +-- <misclib-getmetrics-capi.test.c>.
> +local M = {}
>   
> -local path = arg[0]:gsub('%.test%.lua', '')
> -local suffix = package.cpath:match('?.(%a+);')
> -package.cpath = ('%s/?.%s;'):format(path, suffix)..package.cpath
> +-- XXX: Max nins is limited by max IRRef, that equals to
> +-- REF_DROP - REF_BIAS. Unfortunately, these constants are not
> +-- provided to Lua space, so we ought to make some math:
> +-- * REF_DROP = 0xffff
> +-- * REF_BIAS = 0x8000
> +-- See <src/lj_ir.h> for details.
> +local MAXNINS =  0xffff - 0x8000
>   
> -local MAXNINS = require('utils').const.maxnins
>   local jit_opt_default = {
>       3, -- level
> -    "hotloop=56",
> -    "hotexit=10",
> -    "minstitch=0",
> +    'hotloop=56',
> +    'hotexit=10',
> +    'minstitch=0',
>   }
>   
> -local testgetmetrics = require("testgetmetrics")
> -
> -test:ok(testgetmetrics.base())
> -test:ok(testgetmetrics.gc_allocated_freed())
> -test:ok(testgetmetrics.gc_steps())
> -
> -test:ok(testgetmetrics.objcount(function(iterations)
> -    local ffi = require("ffi")
> -
> +M.objcount = function(iterations)
>       jit.opt.start(0)
>   
>       local placeholder = {
> @@ -51,35 +45,34 @@ test:ok(testgetmetrics.objcount(function(iterations)
>   
>       for _ = 1, iterations do
>           -- Check counting of VLA/VLS/aligned cdata.
> -        table.insert(placeholder.cdata, ffi.new("char[?]", 4))
> +        table.insert(placeholder.cdata, ffi.new('char[?]', 4))
>       end
>   
>       for _ = 1, iterations do
>           -- Check counting of non-VLA/VLS/aligned cdata.
> -        table.insert(placeholder.cdata, ffi.new("uint64_t", _))
> +        table.insert(placeholder.cdata, ffi.new('uint64_t', _))
>       end
>   
>       placeholder = nil -- luacheck: no unused
>       -- Restore default jit settings.
>       jit.opt.start(unpack(jit_opt_default))
> -end))
> +end
>   
> -test:ok(testgetmetrics.objcount_cdata_decrement(function()
> +M.objcount_cdata_decrement = function()
>       -- gc_cdatanum decrement test.
>       -- See https://github.com/tarantool/tarantool/issues/5820.
> -    local ffi = require("ffi")
>       local function nop() end
> -    ffi.gc(ffi.cast("void *", 0), nop)
> +    ffi.gc(ffi.cast('void *', 0), nop)
>       -- Does not collect the cdata, but resurrects the object and
>       -- removes LJ_GC_CDATA_FIN flag.
>       collectgarbage()
>       -- Collects the cdata.
>       collectgarbage()
> -end))
> +end
>   
>   -- Compiled loop with a direct exit to the interpreter.
> -test:ok(testgetmetrics.snap_restores(function()
> -    jit.opt.start(0, "hotloop=1")
> +M.snap_restores_direct_exit = function()
> +    jit.opt.start(0, 'hotloop=1')
>   
>       local sum = 0
>       for i = 1, 20 do
> @@ -91,11 +84,11 @@ test:ok(testgetmetrics.snap_restores(function()
>   
>       -- A single snapshot restoration happened on loop finish.
>       return 1
> -end))
> +end
>   
>   -- Compiled loop with a side exit which does not get compiled.
> -test:ok(testgetmetrics.snap_restores(function()
> -    jit.opt.start(0, "hotloop=1", "hotexit=2", ("minstitch=%d"):format(MAXNINS))
> +M.snap_restores_side_exit_not_compiled = function()
> +    jit.opt.start(0, 'hotloop=1', 'hotexit=2', ('minstitch=%d'):format(MAXNINS))
>   
>       local function foo(i)
>           -- math.fmod is not yet compiled!
> @@ -112,13 +105,13 @@ test:ok(testgetmetrics.snap_restores(function()
>   
>       -- Side exits from the root trace could not get compiled.
>       return 5
> -end))
> +end
>   
>   -- Compiled loop with a side exit which gets compiled.
> -test:ok(testgetmetrics.snap_restores(function()
> +M.snap_restores_side_exit_compiled = function()
>       -- Optimization level is important here as `loop` optimization
>       -- may unroll the loop body and insert +1 side exit.
> -    jit.opt.start(0, "hotloop=1", "hotexit=5")
> +    jit.opt.start(0, 'hotloop=1', 'hotexit=5')
>   
>       local function foo(i)
>           return i <= 10 and i or tostring(i)
> @@ -136,13 +129,13 @@ test:ok(testgetmetrics.snap_restores(function()
>       -- and compiled
>       -- 1 side exit on loop end
>       return 6
> -end))
> +end
>   
>   -- Compiled scalar trace with a direct exit to the interpreter.
> -test:ok(testgetmetrics.snap_restores(function()
> +M.snap_restores_direct_exit_scalar = function()
>       -- For calls it will be 2 * hotloop (see lj_dispatch.{c,h}
>       -- and hotcall at vm_*.dasc).
> -    jit.opt.start(3, "hotloop=2", "hotexit=3")
> +    jit.opt.start(3, 'hotloop=2', 'hotexit=3')
>   
>       local function foo(i)
>           return i <= 15 and i or tostring(i)
> @@ -167,15 +160,15 @@ test:ok(testgetmetrics.snap_restores(function()
>       jit.opt.start(unpack(jit_opt_default))
>   
>       return 2
> -end))
> +end
>   
> -test:ok(testgetmetrics.strhash())
> -
> -test:ok(testgetmetrics.tracenum_base(function()
> +M.tracenum_base = function()
>       local sum = 0
>       for i = 1, 200 do
>           sum = sum + i
>       end
>       -- Compiled only 1 loop as new trace.
>       return 1
> -end))
> +end
> +
> +return M
> diff --git a/test/tarantool-c-tests/misclib-getmetrics-capi.test.c b/test/tarantool-c-tests/misclib-getmetrics-capi.test.c
> new file mode 100644
> index 00000000..202cd395
> --- /dev/null
> +++ b/test/tarantool-c-tests/misclib-getmetrics-capi.test.c
> @@ -0,0 +1,343 @@
> +#include "lua.h"
> +#include "luajit.h"
> +#include "lauxlib.h"
> +#include "lmisclib.h"
> +
> +#include "test.h"
> +#include "utils.h"
> +
> +/* Need for skipcond for BSD and JIT. */
> +#include "lj_arch.h"
> +
> +static int base(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	struct luam_Metrics metrics;
> +	luaM_metrics(L, &metrics);
> +
> +	/*
> +	 * Just check structure format, not values that fields
> +	 * contain.
> +	 */
> +	(void)metrics.strhash_hit;
> +	(void)metrics.strhash_miss;
> +
> +	(void)metrics.gc_strnum;
> +	(void)metrics.gc_tabnum;
> +	(void)metrics.gc_udatanum;
> +	(void)metrics.gc_cdatanum;
> +
> +	(void)metrics.gc_total;
> +	(void)metrics.gc_freed;
> +	(void)metrics.gc_allocated;
> +
> +	(void)metrics.gc_steps_pause;
> +	(void)metrics.gc_steps_propagate;
> +	(void)metrics.gc_steps_atomic;
> +	(void)metrics.gc_steps_sweepstring;
> +	(void)metrics.gc_steps_sweep;
> +	(void)metrics.gc_steps_finalize;
> +
> +	(void)metrics.jit_snap_restore;
> +	(void)metrics.jit_trace_abort;
> +	(void)metrics.jit_mcode_size;
> +	(void)metrics.jit_trace_num;
> +
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int gc_allocated_freed(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	struct luam_Metrics oldm, newm;
> +	/* Force up garbage collect all dead objects. */
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +
> +	luaM_metrics(L, &oldm);
> +	/* Simple garbage generation. */
> +	if (luaL_dostring(L, "local i = 0 for j = 1, 10 do i = i + j end"))
> +		bail_out("failed to translate Lua code snippet");
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +	luaM_metrics(L, &newm);
> +	assert_true(newm.gc_allocated - oldm.gc_allocated > 0);
> +	assert_true(newm.gc_freed - oldm.gc_freed > 0);
> +
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int gc_steps(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	struct luam_Metrics oldm, newm;
> +	/*
> +	 * Some garbage has already happened before the next line,
> +	 * i.e. during frontend processing Lua test chunk.
> +	 * Let's put a full garbage collection cycle on top
> +	 * of that, and confirm that non-null values are reported
> +	 * (we are not yet interested in actual numbers):
> +	 */
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +
> +	luaM_metrics(L, &oldm);
> +	assert_true(oldm.gc_steps_pause > 0);
> +	assert_true(oldm.gc_steps_propagate > 0);
> +	assert_true(oldm.gc_steps_atomic > 0);
> +	assert_true(oldm.gc_steps_sweepstring > 0);
> +	assert_true(oldm.gc_steps_sweep > 0);
> +	/* Nothing to finalize, skipped. */
> +	assert_true(oldm.gc_steps_finalize == 0);
> +
> +	/*
> +	 * As long as we don't create new Lua objects
> +	 * consequent call should return the same values:
> +	 */
> +	luaM_metrics(L, &newm);
> +	assert_sizet_equal(newm.gc_steps_pause, oldm.gc_steps_pause);
> +	assert_sizet_equal(newm.gc_steps_propagate, oldm.gc_steps_propagate);
> +	assert_sizet_equal(newm.gc_steps_atomic, oldm.gc_steps_atomic);
> +	assert_sizet_equal(newm.gc_steps_sweepstring,
> +			   oldm.gc_steps_sweepstring);
> +	assert_sizet_equal(newm.gc_steps_sweep, oldm.gc_steps_sweep);
> +	/* Nothing to finalize, skipped. */
> +	assert_true(newm.gc_steps_finalize == 0);
> +	oldm = newm;
> +
> +	/*
> +	 * Now the last phase: run full GC once and make sure that
> +	 * everything is being reported as expected:
> +	 */
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +	luaM_metrics(L, &newm);
> +	assert_true(newm.gc_steps_pause - oldm.gc_steps_pause == 1);
> +	assert_true(newm.gc_steps_propagate - oldm.gc_steps_propagate >= 1);
> +	assert_true(newm.gc_steps_atomic - oldm.gc_steps_atomic == 1);
> +	assert_true(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring >= 1);
> +	assert_true(newm.gc_steps_sweep - oldm.gc_steps_sweep >= 1);
> +	/* Nothing to finalize, skipped. */
> +	assert_true(newm.gc_steps_finalize == 0);
> +	oldm = newm;
> +
> +	/*
> +	 * Now let's run three GC cycles to ensure that
> +	 * increment was not a lucky coincidence.
> +	 */
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +	luaM_metrics(L, &newm);
> +	assert_true(newm.gc_steps_pause - oldm.gc_steps_pause == 3);
> +	assert_true(newm.gc_steps_propagate - oldm.gc_steps_propagate >= 3);
> +	assert_true(newm.gc_steps_atomic - oldm.gc_steps_atomic == 3);
> +	assert_true(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring >= 3);
> +	assert_true(newm.gc_steps_sweep - oldm.gc_steps_sweep >= 3);
> +	/* Nothing to finalize, skipped. */
> +	assert_true(newm.gc_steps_finalize == 0);
> +
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int objcount(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	struct luam_Metrics oldm, newm;
> +	if (!LJ_HASJIT)
> +		return skip("Test requires JIT enabled");
> +
> +	utils_get_aux_lfunc(L);
> +
> +	/* Force up garbage collect all dead objects. */
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +
> +	luaM_metrics(L, &oldm);
> +	/* Generate garbage. Argument is iterations amount. */
> +	lua_pushnumber(L, 1000);
> +	lua_call(L, 1, 0);
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +	luaM_metrics(L, &newm);
> +	assert_sizet_equal(newm.gc_strnum, oldm.gc_strnum);
> +	assert_sizet_equal(newm.gc_tabnum, oldm.gc_tabnum);
> +	assert_sizet_equal(newm.gc_udatanum, oldm.gc_udatanum);
> +	assert_sizet_equal(newm.gc_cdatanum, oldm.gc_cdatanum);
> +
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int objcount_cdata_decrement(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	/*
> +	 * cdata decrement test.
> +	 * See https://github.com/tarantool/tarantool/issues/5820.
> +	 */
> +	struct luam_Metrics oldm, newm;
> +	utils_get_aux_lfunc(L);
> +
> +	/* Force up garbage collect all dead objects. */
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +
> +	luaM_metrics(L, &oldm);
> +	/*
> +	 * The function generates and collects cdata with
> +	 * LJ_GC_CDATA_FIN flag.
> +	 */
> +	lua_call(L, 0, 0);
> +	luaM_metrics(L, &newm);
> +	assert_sizet_equal(newm.gc_cdatanum, oldm.gc_cdatanum);
> +
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +/*
> + * Get function to call to generate the corresponding snapshot
> + * restores on top of the Lua stack. Function returns the amount
> + * of snapshot restorations expected.
> + * Clear stack after call.
> + */
> +static void check_snap_restores(lua_State *L)
> +{
> +	struct luam_Metrics oldm, newm;
> +	luaM_metrics(L, &oldm);
> +	/* Generate snapshots. */
> +	lua_call(L, 0, 1);
> +	int n = lua_gettop(L);
> +	/*
> +	 * The first value is the table with functions,
> +	 * the second is number of snapshot restores.
> +	 */
> +	if (n != 2 || !lua_isnumber(L, -1))
> +		bail_out("incorrect return value: 1 number is required");
> +	size_t snap_restores = lua_tonumber(L, -1);
> +	luaM_metrics(L, &newm);
> +	/*
> +	 * Remove `snap_restores` from stack.
> +	 * Must be done before potiential assert and exit from
> +	 * the test.
> +	 */
> +	lua_pop(L, 1);
> +	assert_true(newm.jit_snap_restore - oldm.jit_snap_restore
> +		    == snap_restores);
> +}
> +
> +static int snap_restores_direct_exit(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	utils_get_aux_lfunc(L);
> +	check_snap_restores(L);
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int snap_restores_direct_exit_scalar(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	utils_get_aux_lfunc(L);
> +	check_snap_restores(L);
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int snap_restores_side_exit_compiled(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	utils_get_aux_lfunc(L);
> +	check_snap_restores(L);
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int snap_restores_side_exit_not_compiled(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	utils_get_aux_lfunc(L);
> +	check_snap_restores(L);
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int snap_restores_group(void *test_state)
> +{
> +	if (!LJ_HASJIT)
> +		return skip("Test requires JIT enabled");
> +	const struct test_unit tgroup[] = {
> +		test_unit_new(snap_restores_direct_exit),
> +		test_unit_new(snap_restores_direct_exit_scalar),
> +		test_unit_new(snap_restores_side_exit_compiled),
> +		test_unit_new(snap_restores_side_exit_not_compiled)
> +	};
> +	return test_run_group(tgroup, test_state);
> +}
> +
> +static int strhash(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	struct luam_Metrics oldm, newm;
> +	lua_pushstring(L, "strhash_hit");
> +	luaM_metrics(L, &oldm);
> +	lua_pushstring(L, "strhash_hit");
> +	lua_pushstring(L, "new_str");
> +	luaM_metrics(L, &newm);
> +	/* Remove pushed strings. */
> +	lua_pop(L, 3);
> +	assert_true(newm.strhash_hit - oldm.strhash_hit == 1);
> +	assert_true(newm.strhash_miss - oldm.strhash_miss == 1);
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +static int tracenum_base(void *test_state)
> +{
> +	lua_State *L = test_state;
> +	if (!LJ_HASJIT)
> +		return skip("Test requires JIT enabled");
> +	struct luam_Metrics metrics;
> +	utils_get_aux_lfunc(L);
> +
> +	luaJIT_setmode(L, 0, LUAJIT_MODE_FLUSH);
> +	/* Force up garbage collect all dead objects. */
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +
> +	luaM_metrics(L, &metrics);
> +	assert_true(metrics.jit_trace_num == 0);
> +
> +	/* Generate traces. */
> +	lua_call(L, 0, 1);
> +	int n = lua_gettop(L);
> +	/*
> +	 * The first value is the table with functions,
> +	 * the second is the amount of traces.
> +	 */
> +	if (n != 2 || !lua_isnumber(L, -1))
> +		bail_out("incorrect return value: 1 number is required");
> +	size_t jit_trace_num = lua_tonumber(L, -1);
> +	luaM_metrics(L, &metrics);
> +	/* Remove `jit_trace_num` from Lua stack. */
> +	lua_pop(L, 1);
> +
> +	assert_sizet_equal(metrics.jit_trace_num, jit_trace_num);
> +
> +	luaJIT_setmode(L, 0, LUAJIT_MODE_FLUSH);
> +	/* Force up garbage collect all dead objects. */
> +	lua_gc(L, LUA_GCCOLLECT, 0);
> +	luaM_metrics(L, &metrics);
> +	assert_true(metrics.jit_trace_num == 0);
> +
> +	return TEST_EXIT_SUCCESS;
> +}
> +
> +int main(void)
> +{
> +	if (LUAJIT_OS == LUAJIT_OS_BSD)
> +		return skip_all("Disabled on *BSD due to #4819");
> +
> +	lua_State *L = utils_lua_init();
> +
> +	utils_load_aux_script(L);
> +	const struct test_unit tgroup[] = {
> +		test_unit_new(base),
> +		test_unit_new(gc_allocated_freed),
> +		test_unit_new(gc_steps),
> +		test_unit_new(objcount),
> +		test_unit_new(objcount_cdata_decrement),
> +		test_unit_new(snap_restores_group),
> +		test_unit_new(strhash),
> +		test_unit_new(tracenum_base)
> +	};
> +	const int test_result = test_run_group(tgroup, L);
> +	utils_lua_close(L);
> +	return test_result;
> +}
> diff --git a/test/tarantool-tests/CMakeLists.txt b/test/tarantool-tests/CMakeLists.txt
> index 38d6ae49..b4ce39d3 100644
> --- a/test/tarantool-tests/CMakeLists.txt
> +++ b/test/tarantool-tests/CMakeLists.txt
> @@ -66,7 +66,6 @@ add_subdirectory(lj-416-xor-before-jcc)
>   add_subdirectory(lj-601-fix-gc-finderrfunc)
>   add_subdirectory(lj-727-lightuserdata-itern)
>   add_subdirectory(lj-flush-on-trace)
> -add_subdirectory(misclib-getmetrics-capi)
>   add_subdirectory(misclib-sysprof-capi)
>   
>   # The part of the memory profiler toolchain is located in tools
> diff --git a/test/tarantool-tests/misclib-getmetrics-capi/CMakeLists.txt b/test/tarantool-tests/misclib-getmetrics-capi/CMakeLists.txt
> deleted file mode 100644
> index 60eb5bbb..00000000
> --- a/test/tarantool-tests/misclib-getmetrics-capi/CMakeLists.txt
> +++ /dev/null
> @@ -1 +0,0 @@
> -BuildTestCLib(testgetmetrics testgetmetrics.c)
> diff --git a/test/tarantool-tests/misclib-getmetrics-capi/testgetmetrics.c b/test/tarantool-tests/misclib-getmetrics-capi/testgetmetrics.c
> deleted file mode 100644
> index 67776338..00000000
> --- a/test/tarantool-tests/misclib-getmetrics-capi/testgetmetrics.c
> +++ /dev/null
> @@ -1,270 +0,0 @@
> -#include <lua.h>
> -#include <luajit.h>
> -#include <lauxlib.h>
> -
> -#include <lmisclib.h>
> -
> -#undef NDEBUG
> -#include <assert.h>
> -
> -static int base(lua_State *L)
> -{
> -	struct luam_Metrics metrics;
> -	luaM_metrics(L, &metrics);
> -
> -	/* Just check structure format, not values that fields contain. */
> -	(void)metrics.strhash_hit;
> -	(void)metrics.strhash_miss;
> -
> -	(void)metrics.gc_strnum;
> -	(void)metrics.gc_tabnum;
> -	(void)metrics.gc_udatanum;
> -	(void)metrics.gc_cdatanum;
> -
> -	(void)metrics.gc_total;
> -	(void)metrics.gc_freed;
> -	(void)metrics.gc_allocated;
> -
> -	(void)metrics.gc_steps_pause;
> -	(void)metrics.gc_steps_propagate;
> -	(void)metrics.gc_steps_atomic;
> -	(void)metrics.gc_steps_sweepstring;
> -	(void)metrics.gc_steps_sweep;
> -	(void)metrics.gc_steps_finalize;
> -
> -	(void)metrics.jit_snap_restore;
> -	(void)metrics.jit_trace_abort;
> -	(void)metrics.jit_mcode_size;
> -	(void)metrics.jit_trace_num;
> -
> -	lua_pushboolean(L, 1);
> -	return 1;
> -}
> -
> -static int gc_allocated_freed(lua_State *L)
> -{
> -	struct luam_Metrics oldm, newm;
> -	/* Force up garbage collect all dead objects. */
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -
> -	luaM_metrics(L, &oldm);
> -	/* Simple garbage generation. */
> -	if (luaL_dostring(L, "local i = 0 for j = 1, 10 do i = i + j end"))
> -		luaL_error(L, "failed to translate Lua code snippet");
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -	luaM_metrics(L, &newm);
> -	assert(newm.gc_allocated - oldm.gc_allocated > 0);
> -	assert(newm.gc_freed - oldm.gc_freed > 0);
> -
> -	lua_pushboolean(L, 1);
> -	return 1;
> -}
> -
> -static int gc_steps(lua_State *L)
> -{
> -	struct luam_Metrics oldm, newm;
> -	/*
> -	 * Some garbage has already happened before the next line,
> -	 * i.e. during frontend processing Lua test chunk.
> -	 * Let's put a full garbage collection cycle on top
> -	 * of that, and confirm that non-null values are reported
> -	 * (we are not yet interested in actual numbers):
> -	 */
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -
> -	luaM_metrics(L, &oldm);
> -	assert(oldm.gc_steps_pause > 0);
> -	assert(oldm.gc_steps_propagate > 0);
> -	assert(oldm.gc_steps_atomic > 0);
> -	assert(oldm.gc_steps_sweepstring > 0);
> -	assert(oldm.gc_steps_sweep > 0);
> -	/* Nothing to finalize, skipped. */
> -	assert(oldm.gc_steps_finalize == 0);
> -
> -	/*
> -	 * As long as we don't create new Lua objects
> -	 * consequent call should return the same values:
> -	 */
> -	luaM_metrics(L, &newm);
> -	assert(newm.gc_steps_pause - oldm.gc_steps_pause == 0);
> -	assert(newm.gc_steps_propagate - oldm.gc_steps_propagate == 0);
> -	assert(newm.gc_steps_atomic - oldm.gc_steps_atomic == 0);
> -	assert(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring == 0);
> -	assert(newm.gc_steps_sweep - oldm.gc_steps_sweep == 0);
> -	/* Nothing to finalize, skipped. */
> -	assert(newm.gc_steps_finalize == 0);
> -	oldm = newm;
> -
> -	/*
> -	 * Now the last phase: run full GC once and make sure that
> -	 * everything is being reported as expected:
> -	 */
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -	luaM_metrics(L, &newm);
> -	assert(newm.gc_steps_pause - oldm.gc_steps_pause == 1);
> -	assert(newm.gc_steps_propagate - oldm.gc_steps_propagate >= 1);
> -	assert(newm.gc_steps_atomic - oldm.gc_steps_atomic == 1);
> -	assert(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring >= 1);
> -	assert(newm.gc_steps_sweep - oldm.gc_steps_sweep >= 1);
> -	/* Nothing to finalize, skipped. */
> -	assert(newm.gc_steps_finalize == 0);
> -	oldm = newm;
> -
> -	/*
> -	 * Now let's run three GC cycles to ensure that
> -	 * increment was not a lucky coincidence.
> -	 */
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -	luaM_metrics(L, &newm);
> -	assert(newm.gc_steps_pause - oldm.gc_steps_pause == 3);
> -	assert(newm.gc_steps_propagate - oldm.gc_steps_propagate >= 3);
> -	assert(newm.gc_steps_atomic - oldm.gc_steps_atomic == 3);
> -	assert(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring >= 3);
> -	assert(newm.gc_steps_sweep - oldm.gc_steps_sweep >= 3);
> -	/* Nothing to finalize, skipped. */
> -	assert(newm.gc_steps_finalize == 0);
> -
> -	lua_pushboolean(L, 1);
> -	return 1;
> -}
> -
> -static int objcount(lua_State *L)
> -{
> -	struct luam_Metrics oldm, newm;
> -	int n = lua_gettop(L);
> -	if (n != 1 || !lua_isfunction(L, 1))
> -		luaL_error(L, "incorrect argument: 1 function is required");
> -
> -	/* Force up garbage collect all dead objects. */
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -
> -	luaM_metrics(L, &oldm);
> -	/* Generate garbage. Argument is iterations amount. */
> -	lua_pushnumber(L, 1000);
> -	lua_call(L, 1, 0);
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -	luaM_metrics(L, &newm);
> -	assert(newm.gc_strnum - oldm.gc_strnum == 0);
> -	assert(newm.gc_tabnum - oldm.gc_tabnum == 0);
> -	assert(newm.gc_udatanum - oldm.gc_udatanum == 0);
> -	assert(newm.gc_cdatanum - oldm.gc_cdatanum == 0);
> -
> -	lua_pushboolean(L, 1);
> -	return 1;
> -}
> -
> -static int objcount_cdata_decrement(lua_State *L)
> -{
> -	/*
> -	 * cdata decrement test.
> -	 * See https://github.com/tarantool/tarantool/issues/5820.
> -	 */
> -	struct luam_Metrics oldm, newm;
> -	int n = lua_gettop(L);
> -	if (n != 1 || !lua_isfunction(L, 1))
> -		luaL_error(L, "incorrect argument: 1 function is required");
> -
> -	/* Force up garbage collect all dead objects. */
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -
> -	luaM_metrics(L, &oldm);
> -	/*
> -	 * The function generates and collects cdata with
> -	 * LJ_GC_CDATA_FIN flag.
> -	 */
> -	lua_call(L, 0, 0);
> -	luaM_metrics(L, &newm);
> -	assert(newm.gc_cdatanum - oldm.gc_cdatanum == 0);
> -
> -	lua_pushboolean(L, 1);
> -	return 1;
> -}
> -
> -static int snap_restores(lua_State *L)
> -{
> -	struct luam_Metrics oldm, newm;
> -	int n = lua_gettop(L);
> -	if (n != 1 || !lua_isfunction(L, 1))
> -		luaL_error(L, "incorrect arguments: 1 function is required");
> -
> -	luaM_metrics(L, &oldm);
> -	/* Generate snapshots. */
> -	lua_call(L, 0, 1);
> -	n = lua_gettop(L);
> -	if (n != 1 || !lua_isnumber(L, 1))
> -		luaL_error(L, "incorrect return value: 1 number is required");
> -	size_t snap_restores = lua_tonumber(L, 1);
> -	luaM_metrics(L, &newm);
> -	assert(newm.jit_snap_restore - oldm.jit_snap_restore == snap_restores);
> -
> -	lua_pushboolean(L, 1);
> -	return 1;
> -}
> -
> -static int strhash(lua_State *L)
> -{
> -	struct luam_Metrics oldm, newm;
> -	lua_pushstring(L, "strhash_hit");
> -	luaM_metrics(L, &oldm);
> -	lua_pushstring(L, "strhash_hit");
> -	lua_pushstring(L, "new_str");
> -	luaM_metrics(L, &newm);
> -	assert(newm.strhash_hit - oldm.strhash_hit == 1);
> -	assert(newm.strhash_miss - oldm.strhash_miss == 1);
> -	lua_pop(L, 3);
> -	lua_pushboolean(L, 1);
> -	return 1;
> -}
> -
> -static int tracenum_base(lua_State *L)
> -{
> -	struct luam_Metrics metrics;
> -	int n = lua_gettop(L);
> -	if (n != 1 || !lua_isfunction(L, 1))
> -		luaL_error(L, "incorrect arguments: 1 function is required");
> -
> -	luaJIT_setmode(L, 0, LUAJIT_MODE_FLUSH);
> -	/* Force up garbage collect all dead objects. */
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -
> -	luaM_metrics(L, &metrics);
> -	assert(metrics.jit_trace_num == 0);
> -
> -	/* Generate traces. */
> -	lua_call(L, 0, 1);
> -	n = lua_gettop(L);
> -	if (n != 1 || !lua_isnumber(L, 1))
> -		luaL_error(L, "incorrect return value: 1 number is required");
> -	size_t jit_trace_num = lua_tonumber(L, 1);
> -	luaM_metrics(L, &metrics);
> -	assert(metrics.jit_trace_num == jit_trace_num);
> -
> -	luaJIT_setmode(L, 0, LUAJIT_MODE_FLUSH);
> -	/* Force up garbage collect all dead objects. */
> -	lua_gc(L, LUA_GCCOLLECT, 0);
> -	luaM_metrics(L, &metrics);
> -	assert(metrics.jit_trace_num == 0);
> -
> -	lua_pushboolean(L, 1);
> -	return 1;
> -}
> -
> -static const struct luaL_Reg testgetmetrics[] = {
> -	{"base", base},
> -	{"gc_allocated_freed", gc_allocated_freed},
> -	{"gc_steps", gc_steps},
> -	{"objcount", objcount},
> -	{"objcount_cdata_decrement", objcount_cdata_decrement},
> -	{"snap_restores", snap_restores},
> -	{"strhash", strhash},
> -	{"tracenum_base", tracenum_base},
> -	{NULL, NULL}
> -};
> -
> -LUA_API int luaopen_testgetmetrics(lua_State *L)
> -{
> -	luaL_register(L, "testgetmetrics", testgetmetrics);
> -	return 1;
> -}


More information about the Tarantool-patches mailing list