Hi, Sergey Thanks for the patch. LGTM, except for a few comments below.   >  >>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 , 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 drop a comment explaining the line above. >  > >> >>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 > >>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); >I think it is better to create a for loop here. >>+ 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); >That part is duplicated. It is better to either write a corresponding macro, or >a function. >>+ /* 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; >>+} >>+ >Same here. Either a dedicated implementation func, or a macro is needed here. >>+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 >>-#include >>-#include >>- >>-#include >>- >>-#undef NDEBUG >>-#include >>- >>-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; >>-} >>-- >>2.34.1 >-- >Best regards, >Maxim Kokryashkin >