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

Maxim Kokryashkin m.kokryashkin at tarantool.org
Fri May 19 15:17:57 MSK 2023


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 <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 drop a comment explaining the line above.
> 
><snipped>
>>
>>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
><snipped>
>>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 <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;
>>-}
>>--
>>2.34.1
>--
>Best regards,
>Maxim Kokryashkin
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.tarantool.org/pipermail/tarantool-patches/attachments/20230519/31fde76e/attachment.htm>


More information about the Tarantool-patches mailing list