<HTML><BODY><div>Hi, Sergey</div><div>Thanks for the patch.</div><div>LGTM, except for a few comments below.</div><div> </div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;"><div> <blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;"><div id=""><div class="js-helper js-readmsg-msg"><div><div id="style_16844429441363206197_BODY">This patch rewrites the aforementioned test with the usage libtest,<br>recently introduced. Since we still stand in need of a Lua helper script<br>for generation of traces, the original test file is reworked as a<br>standalone script, which returns the table with helper functions. Each<br>helper function is named the same as the test where it will be used. Now<br>single quotes are used according to our Lua code style.<br><br>In C part all asserts from glibc are replaced with the corresponding<br>assert_{cond} from the libtest. Now tests return `TEST_EXIT_SUCCESS` at<br>the finish. Also, the stack check for the amount of return results from<br>the helper function is slightly changed, since there is one more stack<br>slot in use (table with these functions). `snap_restores()` C function<br>duplicates 4 times for each subtest. Common helper<br>`check_snap_restores()` is used for each of them. Each error throwing is<br>replaced with `bail_out()` call.<br><br>NB: `lua_pop()` to clear the Lua stack after a call should be done before<br>any possible assertion, which would exit from the test leaving the stack<br>uncleaned.<br><br>All skipconds use macros defined in <lj_arch.h>, so it is included in<br>the test. As far as this test initializes the LuaJIT VM manually, there<br>is no need to check `jit.status()` result; checking `LJ_HASJIT` is<br>enough. Now, only JIT-related tests are skipped, when compiled without<br>JIT. Nevertheless, all tests are skipped for *BSD arches.<br><br>Also, this patch sets the new CMake variable named `LUAJIT_LIBRARY`<br>equal to `LUAJIT_LIB` in `PARENT_SCOPE` to be used in tarantool-c-tests<br>linking.<br><br>Also, .c_test suffix is added to the <.gitignore>.<br><br>Part of tarantool/tarantool#7900<br>---<br> .gitignore | 1 +<br> src/CMakeLists.txt | 2 +<br> test/tarantool-c-tests/CMakeLists.txt | 32 +-<br> .../misclib-getmetrics-capi-script.lua} | 83 ++---<br> .../misclib-getmetrics-capi.test.c | 343 ++++++++++++++++++<br> test/tarantool-tests/CMakeLists.txt | 1 -<br> .../misclib-getmetrics-capi/CMakeLists.txt | 1 -<br> .../misclib-getmetrics-capi/testgetmetrics.c | 270 --------------<br> 8 files changed, 412 insertions(+), 321 deletions(-)<br> rename test/{tarantool-tests/misclib-getmetrics-capi.test.lua => tarantool-c-tests/misclib-getmetrics-capi-script.lua} (68%)<br> create mode 100644 test/tarantool-c-tests/misclib-getmetrics-capi.test.c<br> delete mode 100644 test/tarantool-tests/misclib-getmetrics-capi/CMakeLists.txt<br> delete mode 100644 test/tarantool-tests/misclib-getmetrics-capi/testgetmetrics.c<br><br>diff --git a/.gitignore b/.gitignore<br>index b7908aee..dc5ea5fc 100644<br>--- a/.gitignore<br>+++ b/.gitignore<br>@@ -24,3 +24,4 @@ install_manifest.txt<br> luajit-parse-memprof<br> luajit-parse-sysprof<br> luajit.pc<br>+*.c_test<br>diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt<br>index dffc0a4d..fed4c38d 100644<br>--- a/src/CMakeLists.txt<br>+++ b/src/CMakeLists.txt<br>@@ -325,6 +325,8 @@ if(NOT BUILDMODE STREQUAL "dynamic")<br>   set(LUAJIT_BIN luajit_static)<br>   set(LUAJIT_LIB libluajit_static)<br> endif()<br>+# Need for the test linking, so the PARENT_SCOPE option is used.<br>+set(LUAJIT_LIBRARY ${LUAJIT_LIB} PARENT_SCOPE)<br> set(LIBLUAJIT_DEPS ${LIBLUAJIT_STATIC_DEPS} ${LIBLUAJIT_SHARED_DEPS})<br> <br> add_executable(${LUAJIT_BIN} EXCLUDE_FROM_ALL ${CLI_SOURCES})<br>diff --git a/test/tarantool-c-tests/CMakeLists.txt b/test/tarantool-c-tests/CMakeLists.txt<br>index c6b7cd30..c9d75d6c 100644<br>--- a/test/tarantool-c-tests/CMakeLists.txt<br>+++ b/test/tarantool-c-tests/CMakeLists.txt<br>@@ -22,13 +22,37 @@ set_target_properties(libtest PROPERTIES<br>   LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"<br> )<br> <br>-# XXX: For now, just build libtest. The tests to be depended on<br>-# will be added in the next commit.<br>+# TARGET_C_FLAGS is required here to be sure that headers like<br>+# lj_arch.h in compiled test are consistent with the LuaJIT library<br>+# to link.<br>+AppendFlags(TESTS_C_FLAGS ${TARGET_C_FLAGS})<br>+<br>+set(CTEST_SRC_SUFFIX ".test.c")<br>+file(GLOB tests "${CMAKE_CURRENT_SOURCE_DIR}/*${CTEST_SRC_SUFFIX}")<br>+foreach(test_source ${tests})</div></div></div></div></blockquote><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;"><div><div class="js-helper js-readmsg-msg"><div><div>+ string(REGEX REPLACE ".+/([^/]+)${CTEST_SRC_SUFFIX}" "\\1" exe ${test_source})</div></div></div></div></blockquote><div>Please drop a comment explaining the line above.</div><div> </div><div><snipped></div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;"><div><div class="js-helper js-readmsg-msg"><div><div><br>diff --git a/test/tarantool-tests/misclib-getmetrics-capi.test.lua b/test/tarantool-c-tests/misclib-getmetrics-capi-script.lua<br>similarity index 68%<br>rename from test/tarantool-tests/misclib-getmetrics-capi.test.lua<br>rename to test/tarantool-c-tests/misclib-getmetrics-capi-script.lua<br>index 654e5545..2f0ee5cf 100644<br>--- a/test/tarantool-tests/misclib-getmetrics-capi.test.lua<br>+++ b/test/tarantool-c-tests/misclib-getmetrics-capi-script.lua</div></div></div></div></blockquote><div><snipped></div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;"><div><div class="js-helper js-readmsg-msg"><div><div>diff --git a/test/tarantool-c-tests/misclib-getmetrics-capi.test.c b/test/tarantool-c-tests/misclib-getmetrics-capi.test.c<br>new file mode 100644<br>index 00000000..202cd395<br>--- /dev/null<br>+++ b/test/tarantool-c-tests/misclib-getmetrics-capi.test.c<br>@@ -0,0 +1,343 @@<br>+#include "lua.h"<br>+#include "luajit.h"<br>+#include "lauxlib.h"<br>+#include "lmisclib.h"<br>+<br>+#include "test.h"<br>+#include "utils.h"<br>+<br>+/* Need for skipcond for BSD and JIT. */<br>+#include "lj_arch.h"<br>+<br>+static int base(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ struct luam_Metrics metrics;<br>+ luaM_metrics(L, &metrics);<br>+<br>+ /*<br>+ * Just check structure format, not values that fields<br>+ * contain.<br>+ */<br>+ (void)metrics.strhash_hit;<br>+ (void)metrics.strhash_miss;<br>+<br>+ (void)metrics.gc_strnum;<br>+ (void)metrics.gc_tabnum;<br>+ (void)metrics.gc_udatanum;<br>+ (void)metrics.gc_cdatanum;<br>+<br>+ (void)metrics.gc_total;<br>+ (void)metrics.gc_freed;<br>+ (void)metrics.gc_allocated;<br>+<br>+ (void)metrics.gc_steps_pause;<br>+ (void)metrics.gc_steps_propagate;<br>+ (void)metrics.gc_steps_atomic;<br>+ (void)metrics.gc_steps_sweepstring;<br>+ (void)metrics.gc_steps_sweep;<br>+ (void)metrics.gc_steps_finalize;<br>+<br>+ (void)metrics.jit_snap_restore;<br>+ (void)metrics.jit_trace_abort;<br>+ (void)metrics.jit_mcode_size;<br>+ (void)metrics.jit_trace_num;<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int gc_allocated_freed(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ struct luam_Metrics oldm, newm;<br>+ /* Force up garbage collect all dead objects. */<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+<br>+ luaM_metrics(L, &oldm);<br>+ /* Simple garbage generation. */<br>+ if (luaL_dostring(L, "local i = 0 for j = 1, 10 do i = i + j end"))<br>+ bail_out("failed to translate Lua code snippet");<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+ luaM_metrics(L, &newm);<br>+ assert_true(newm.gc_allocated - oldm.gc_allocated > 0);<br>+ assert_true(newm.gc_freed - oldm.gc_freed > 0);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int gc_steps(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ struct luam_Metrics oldm, newm;<br>+ /*<br>+ * Some garbage has already happened before the next line,<br>+ * i.e. during frontend processing Lua test chunk.<br>+ * Let's put a full garbage collection cycle on top<br>+ * of that, and confirm that non-null values are reported<br>+ * (we are not yet interested in actual numbers):<br>+ */<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+<br>+ luaM_metrics(L, &oldm);<br>+ assert_true(oldm.gc_steps_pause > 0);<br>+ assert_true(oldm.gc_steps_propagate > 0);<br>+ assert_true(oldm.gc_steps_atomic > 0);<br>+ assert_true(oldm.gc_steps_sweepstring > 0);<br>+ assert_true(oldm.gc_steps_sweep > 0);<br>+ /* Nothing to finalize, skipped. */<br>+ assert_true(oldm.gc_steps_finalize == 0);<br>+<br>+ /*<br>+ * As long as we don't create new Lua objects<br>+ * consequent call should return the same values:<br>+ */<br>+ luaM_metrics(L, &newm);<br>+ assert_sizet_equal(newm.gc_steps_pause, oldm.gc_steps_pause);<br>+ assert_sizet_equal(newm.gc_steps_propagate, oldm.gc_steps_propagate);<br>+ assert_sizet_equal(newm.gc_steps_atomic, oldm.gc_steps_atomic);<br>+ assert_sizet_equal(newm.gc_steps_sweepstring,<br>+ oldm.gc_steps_sweepstring);<br>+ assert_sizet_equal(newm.gc_steps_sweep, oldm.gc_steps_sweep);<br>+ /* Nothing to finalize, skipped. */<br>+ assert_true(newm.gc_steps_finalize == 0);<br>+ oldm = newm;<br>+<br>+ /*<br>+ * Now the last phase: run full GC once and make sure that<br>+ * everything is being reported as expected:<br>+ */<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+ luaM_metrics(L, &newm);<br>+ assert_true(newm.gc_steps_pause - oldm.gc_steps_pause == 1);<br>+ assert_true(newm.gc_steps_propagate - oldm.gc_steps_propagate >= 1);<br>+ assert_true(newm.gc_steps_atomic - oldm.gc_steps_atomic == 1);<br>+ assert_true(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring >= 1);<br>+ assert_true(newm.gc_steps_sweep - oldm.gc_steps_sweep >= 1);<br>+ /* Nothing to finalize, skipped. */<br>+ assert_true(newm.gc_steps_finalize == 0);<br>+ oldm = newm;<br>+<br>+ /*<br>+ * Now let's run three GC cycles to ensure that<br>+ * increment was not a lucky coincidence.<br>+ */<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+ lua_gc(L, LUA_GCCOLLECT, 0);</div></div></div></div></blockquote><div>I think it is better to create a for loop here.</div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;"><div><div class="js-helper js-readmsg-msg"><div><div>+ luaM_metrics(L, &newm);<br>+ assert_true(newm.gc_steps_pause - oldm.gc_steps_pause == 3);<br>+ assert_true(newm.gc_steps_propagate - oldm.gc_steps_propagate >= 3);<br>+ assert_true(newm.gc_steps_atomic - oldm.gc_steps_atomic == 3);<br>+ assert_true(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring >= 3);<br>+ assert_true(newm.gc_steps_sweep - oldm.gc_steps_sweep >= 3);</div></div></div></div></blockquote><div>That part is duplicated. It is better to either write a corresponding macro, or</div><div>a function.</div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;"><div><div class="js-helper js-readmsg-msg"><div><div>+ /* Nothing to finalize, skipped. */<br>+ assert_true(newm.gc_steps_finalize == 0);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int objcount(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ struct luam_Metrics oldm, newm;<br>+ if (!LJ_HASJIT)<br>+ return skip("Test requires JIT enabled");<br>+<br>+ utils_get_aux_lfunc(L);<br>+<br>+ /* Force up garbage collect all dead objects. */<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+<br>+ luaM_metrics(L, &oldm);<br>+ /* Generate garbage. Argument is iterations amount. */<br>+ lua_pushnumber(L, 1000);<br>+ lua_call(L, 1, 0);<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+ luaM_metrics(L, &newm);<br>+ assert_sizet_equal(newm.gc_strnum, oldm.gc_strnum);<br>+ assert_sizet_equal(newm.gc_tabnum, oldm.gc_tabnum);<br>+ assert_sizet_equal(newm.gc_udatanum, oldm.gc_udatanum);<br>+ assert_sizet_equal(newm.gc_cdatanum, oldm.gc_cdatanum);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int objcount_cdata_decrement(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ /*<br>+ * cdata decrement test.<br>+ * See <a href="https://github.com/tarantool/tarantool/issues/5820" target="_blank">https://github.com/tarantool/tarantool/issues/5820</a>.<br>+ */<br>+ struct luam_Metrics oldm, newm;<br>+ utils_get_aux_lfunc(L);<br>+<br>+ /* Force up garbage collect all dead objects. */<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+<br>+ luaM_metrics(L, &oldm);<br>+ /*<br>+ * The function generates and collects cdata with<br>+ * LJ_GC_CDATA_FIN flag.<br>+ */<br>+ lua_call(L, 0, 0);<br>+ luaM_metrics(L, &newm);<br>+ assert_sizet_equal(newm.gc_cdatanum, oldm.gc_cdatanum);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+/*<br>+ * Get function to call to generate the corresponding snapshot<br>+ * restores on top of the Lua stack. Function returns the amount<br>+ * of snapshot restorations expected.<br>+ * Clear stack after call.<br>+ */<br>+static void check_snap_restores(lua_State *L)<br>+{<br>+ struct luam_Metrics oldm, newm;<br>+ luaM_metrics(L, &oldm);<br>+ /* Generate snapshots. */<br>+ lua_call(L, 0, 1);<br>+ int n = lua_gettop(L);<br>+ /*<br>+ * The first value is the table with functions,<br>+ * the second is number of snapshot restores.<br>+ */<br>+ if (n != 2 || !lua_isnumber(L, -1))<br>+ bail_out("incorrect return value: 1 number is required");<br>+ size_t snap_restores = lua_tonumber(L, -1);<br>+ luaM_metrics(L, &newm);<br>+ /*<br>+ * Remove `snap_restores` from stack.<br>+ * Must be done before potiential assert and exit from<br>+ * the test.<br>+ */<br>+ lua_pop(L, 1);<br>+ assert_true(newm.jit_snap_restore - oldm.jit_snap_restore<br>+ == snap_restores);<br>+}<br>+<br>+static int snap_restores_direct_exit(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ utils_get_aux_lfunc(L);<br>+ check_snap_restores(L);<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int snap_restores_direct_exit_scalar(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ utils_get_aux_lfunc(L);<br>+ check_snap_restores(L);<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int snap_restores_side_exit_compiled(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ utils_get_aux_lfunc(L);<br>+ check_snap_restores(L);<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int snap_restores_side_exit_not_compiled(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ utils_get_aux_lfunc(L);<br>+ check_snap_restores(L);<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+</div></div></div></div></blockquote><div>Same here. Either a dedicated implementation func, or a macro is needed here.</div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;"><div><div class="js-helper js-readmsg-msg"><div><div>+static int snap_restores_group(void *test_state)<br>+{<br>+ if (!LJ_HASJIT)<br>+ return skip("Test requires JIT enabled");<br>+ const struct test_unit tgroup[] = {<br>+ test_unit_new(snap_restores_direct_exit),<br>+ test_unit_new(snap_restores_direct_exit_scalar),<br>+ test_unit_new(snap_restores_side_exit_compiled),<br>+ test_unit_new(snap_restores_side_exit_not_compiled)<br>+ };<br>+ return test_run_group(tgroup, test_state);<br>+}<br>+<br>+static int strhash(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ struct luam_Metrics oldm, newm;<br>+ lua_pushstring(L, "strhash_hit");<br>+ luaM_metrics(L, &oldm);<br>+ lua_pushstring(L, "strhash_hit");<br>+ lua_pushstring(L, "new_str");<br>+ luaM_metrics(L, &newm);<br>+ /* Remove pushed strings. */<br>+ lua_pop(L, 3);<br>+ assert_true(newm.strhash_hit - oldm.strhash_hit == 1);<br>+ assert_true(newm.strhash_miss - oldm.strhash_miss == 1);<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int tracenum_base(void *test_state)<br>+{<br>+ lua_State *L = test_state;<br>+ if (!LJ_HASJIT)<br>+ return skip("Test requires JIT enabled");<br>+ struct luam_Metrics metrics;<br>+ utils_get_aux_lfunc(L);<br>+<br>+ luaJIT_setmode(L, 0, LUAJIT_MODE_FLUSH);<br>+ /* Force up garbage collect all dead objects. */<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+<br>+ luaM_metrics(L, &metrics);<br>+ assert_true(metrics.jit_trace_num == 0);<br>+<br>+ /* Generate traces. */<br>+ lua_call(L, 0, 1);<br>+ int n = lua_gettop(L);<br>+ /*<br>+ * The first value is the table with functions,<br>+ * the second is the amount of traces.<br>+ */<br>+ if (n != 2 || !lua_isnumber(L, -1))<br>+ bail_out("incorrect return value: 1 number is required");<br>+ size_t jit_trace_num = lua_tonumber(L, -1);<br>+ luaM_metrics(L, &metrics);<br>+ /* Remove `jit_trace_num` from Lua stack. */<br>+ lua_pop(L, 1);<br>+<br>+ assert_sizet_equal(metrics.jit_trace_num, jit_trace_num);<br>+<br>+ luaJIT_setmode(L, 0, LUAJIT_MODE_FLUSH);<br>+ /* Force up garbage collect all dead objects. */<br>+ lua_gc(L, LUA_GCCOLLECT, 0);<br>+ luaM_metrics(L, &metrics);<br>+ assert_true(metrics.jit_trace_num == 0);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+int main(void)<br>+{<br>+ if (LUAJIT_OS == LUAJIT_OS_BSD)<br>+ return skip_all("Disabled on *BSD due to #4819");<br>+<br>+ lua_State *L = utils_lua_init();<br>+<br>+ utils_load_aux_script(L);<br>+ const struct test_unit tgroup[] = {<br>+ test_unit_new(base),<br>+ test_unit_new(gc_allocated_freed),<br>+ test_unit_new(gc_steps),<br>+ test_unit_new(objcount),<br>+ test_unit_new(objcount_cdata_decrement),<br>+ test_unit_new(snap_restores_group),<br>+ test_unit_new(strhash),<br>+ test_unit_new(tracenum_base)<br>+ };<br>+ const int test_result = test_run_group(tgroup, L);<br>+ utils_lua_close(L);<br>+ return test_result;<br>+}<br>diff --git a/test/tarantool-tests/CMakeLists.txt b/test/tarantool-tests/CMakeLists.txt<br>index 38d6ae49..b4ce39d3 100644<br>--- a/test/tarantool-tests/CMakeLists.txt<br>+++ b/test/tarantool-tests/CMakeLists.txt<br>@@ -66,7 +66,6 @@ add_subdirectory(lj-416-xor-before-jcc)<br> add_subdirectory(lj-601-fix-gc-finderrfunc)<br> add_subdirectory(lj-727-lightuserdata-itern)<br> add_subdirectory(lj-flush-on-trace)<br>-add_subdirectory(misclib-getmetrics-capi)<br> add_subdirectory(misclib-sysprof-capi)<br> <br> # The part of the memory profiler toolchain is located in tools<br>diff --git a/test/tarantool-tests/misclib-getmetrics-capi/CMakeLists.txt b/test/tarantool-tests/misclib-getmetrics-capi/CMakeLists.txt<br>deleted file mode 100644<br>index 60eb5bbb..00000000<br>--- a/test/tarantool-tests/misclib-getmetrics-capi/CMakeLists.txt<br>+++ /dev/null<br>@@ -1 +0,0 @@<br>-BuildTestCLib(testgetmetrics testgetmetrics.c)<br>diff --git a/test/tarantool-tests/misclib-getmetrics-capi/testgetmetrics.c b/test/tarantool-tests/misclib-getmetrics-capi/testgetmetrics.c<br>deleted file mode 100644<br>index 67776338..00000000<br>--- a/test/tarantool-tests/misclib-getmetrics-capi/testgetmetrics.c<br>+++ /dev/null<br>@@ -1,270 +0,0 @@<br>-#include <lua.h><br>-#include <luajit.h><br>-#include <lauxlib.h><br>-<br>-#include <lmisclib.h><br>-<br>-#undef NDEBUG<br>-#include <assert.h><br>-<br>-static int base(lua_State *L)<br>-{<br>- struct luam_Metrics metrics;<br>- luaM_metrics(L, &metrics);<br>-<br>- /* Just check structure format, not values that fields contain. */<br>- (void)metrics.strhash_hit;<br>- (void)metrics.strhash_miss;<br>-<br>- (void)metrics.gc_strnum;<br>- (void)metrics.gc_tabnum;<br>- (void)metrics.gc_udatanum;<br>- (void)metrics.gc_cdatanum;<br>-<br>- (void)metrics.gc_total;<br>- (void)metrics.gc_freed;<br>- (void)metrics.gc_allocated;<br>-<br>- (void)metrics.gc_steps_pause;<br>- (void)metrics.gc_steps_propagate;<br>- (void)metrics.gc_steps_atomic;<br>- (void)metrics.gc_steps_sweepstring;<br>- (void)metrics.gc_steps_sweep;<br>- (void)metrics.gc_steps_finalize;<br>-<br>- (void)metrics.jit_snap_restore;<br>- (void)metrics.jit_trace_abort;<br>- (void)metrics.jit_mcode_size;<br>- (void)metrics.jit_trace_num;<br>-<br>- lua_pushboolean(L, 1);<br>- return 1;<br>-}<br>-<br>-static int gc_allocated_freed(lua_State *L)<br>-{<br>- struct luam_Metrics oldm, newm;<br>- /* Force up garbage collect all dead objects. */<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>-<br>- luaM_metrics(L, &oldm);<br>- /* Simple garbage generation. */<br>- if (luaL_dostring(L, "local i = 0 for j = 1, 10 do i = i + j end"))<br>- luaL_error(L, "failed to translate Lua code snippet");<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>- luaM_metrics(L, &newm);<br>- assert(newm.gc_allocated - oldm.gc_allocated > 0);<br>- assert(newm.gc_freed - oldm.gc_freed > 0);<br>-<br>- lua_pushboolean(L, 1);<br>- return 1;<br>-}<br>-<br>-static int gc_steps(lua_State *L)<br>-{<br>- struct luam_Metrics oldm, newm;<br>- /*<br>- * Some garbage has already happened before the next line,<br>- * i.e. during frontend processing Lua test chunk.<br>- * Let's put a full garbage collection cycle on top<br>- * of that, and confirm that non-null values are reported<br>- * (we are not yet interested in actual numbers):<br>- */<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>-<br>- luaM_metrics(L, &oldm);<br>- assert(oldm.gc_steps_pause > 0);<br>- assert(oldm.gc_steps_propagate > 0);<br>- assert(oldm.gc_steps_atomic > 0);<br>- assert(oldm.gc_steps_sweepstring > 0);<br>- assert(oldm.gc_steps_sweep > 0);<br>- /* Nothing to finalize, skipped. */<br>- assert(oldm.gc_steps_finalize == 0);<br>-<br>- /*<br>- * As long as we don't create new Lua objects<br>- * consequent call should return the same values:<br>- */<br>- luaM_metrics(L, &newm);<br>- assert(newm.gc_steps_pause - oldm.gc_steps_pause == 0);<br>- assert(newm.gc_steps_propagate - oldm.gc_steps_propagate == 0);<br>- assert(newm.gc_steps_atomic - oldm.gc_steps_atomic == 0);<br>- assert(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring == 0);<br>- assert(newm.gc_steps_sweep - oldm.gc_steps_sweep == 0);<br>- /* Nothing to finalize, skipped. */<br>- assert(newm.gc_steps_finalize == 0);<br>- oldm = newm;<br>-<br>- /*<br>- * Now the last phase: run full GC once and make sure that<br>- * everything is being reported as expected:<br>- */<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>- luaM_metrics(L, &newm);<br>- assert(newm.gc_steps_pause - oldm.gc_steps_pause == 1);<br>- assert(newm.gc_steps_propagate - oldm.gc_steps_propagate >= 1);<br>- assert(newm.gc_steps_atomic - oldm.gc_steps_atomic == 1);<br>- assert(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring >= 1);<br>- assert(newm.gc_steps_sweep - oldm.gc_steps_sweep >= 1);<br>- /* Nothing to finalize, skipped. */<br>- assert(newm.gc_steps_finalize == 0);<br>- oldm = newm;<br>-<br>- /*<br>- * Now let's run three GC cycles to ensure that<br>- * increment was not a lucky coincidence.<br>- */<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>- luaM_metrics(L, &newm);<br>- assert(newm.gc_steps_pause - oldm.gc_steps_pause == 3);<br>- assert(newm.gc_steps_propagate - oldm.gc_steps_propagate >= 3);<br>- assert(newm.gc_steps_atomic - oldm.gc_steps_atomic == 3);<br>- assert(newm.gc_steps_sweepstring - oldm.gc_steps_sweepstring >= 3);<br>- assert(newm.gc_steps_sweep - oldm.gc_steps_sweep >= 3);<br>- /* Nothing to finalize, skipped. */<br>- assert(newm.gc_steps_finalize == 0);<br>-<br>- lua_pushboolean(L, 1);<br>- return 1;<br>-}<br>-<br>-static int objcount(lua_State *L)<br>-{<br>- struct luam_Metrics oldm, newm;<br>- int n = lua_gettop(L);<br>- if (n != 1 || !lua_isfunction(L, 1))<br>- luaL_error(L, "incorrect argument: 1 function is required");<br>-<br>- /* Force up garbage collect all dead objects. */<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>-<br>- luaM_metrics(L, &oldm);<br>- /* Generate garbage. Argument is iterations amount. */<br>- lua_pushnumber(L, 1000);<br>- lua_call(L, 1, 0);<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>- luaM_metrics(L, &newm);<br>- assert(newm.gc_strnum - oldm.gc_strnum == 0);<br>- assert(newm.gc_tabnum - oldm.gc_tabnum == 0);<br>- assert(newm.gc_udatanum - oldm.gc_udatanum == 0);<br>- assert(newm.gc_cdatanum - oldm.gc_cdatanum == 0);<br>-<br>- lua_pushboolean(L, 1);<br>- return 1;<br>-}<br>-<br>-static int objcount_cdata_decrement(lua_State *L)<br>-{<br>- /*<br>- * cdata decrement test.<br>- * See <a href="https://github.com/tarantool/tarantool/issues/5820" target="_blank">https://github.com/tarantool/tarantool/issues/5820</a>.<br>- */<br>- struct luam_Metrics oldm, newm;<br>- int n = lua_gettop(L);<br>- if (n != 1 || !lua_isfunction(L, 1))<br>- luaL_error(L, "incorrect argument: 1 function is required");<br>-<br>- /* Force up garbage collect all dead objects. */<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>-<br>- luaM_metrics(L, &oldm);<br>- /*<br>- * The function generates and collects cdata with<br>- * LJ_GC_CDATA_FIN flag.<br>- */<br>- lua_call(L, 0, 0);<br>- luaM_metrics(L, &newm);<br>- assert(newm.gc_cdatanum - oldm.gc_cdatanum == 0);<br>-<br>- lua_pushboolean(L, 1);<br>- return 1;<br>-}<br>-<br>-static int snap_restores(lua_State *L)<br>-{<br>- struct luam_Metrics oldm, newm;<br>- int n = lua_gettop(L);<br>- if (n != 1 || !lua_isfunction(L, 1))<br>- luaL_error(L, "incorrect arguments: 1 function is required");<br>-<br>- luaM_metrics(L, &oldm);<br>- /* Generate snapshots. */<br>- lua_call(L, 0, 1);<br>- n = lua_gettop(L);<br>- if (n != 1 || !lua_isnumber(L, 1))<br>- luaL_error(L, "incorrect return value: 1 number is required");<br>- size_t snap_restores = lua_tonumber(L, 1);<br>- luaM_metrics(L, &newm);<br>- assert(newm.jit_snap_restore - oldm.jit_snap_restore == snap_restores);<br>-<br>- lua_pushboolean(L, 1);<br>- return 1;<br>-}<br>-<br>-static int strhash(lua_State *L)<br>-{<br>- struct luam_Metrics oldm, newm;<br>- lua_pushstring(L, "strhash_hit");<br>- luaM_metrics(L, &oldm);<br>- lua_pushstring(L, "strhash_hit");<br>- lua_pushstring(L, "new_str");<br>- luaM_metrics(L, &newm);<br>- assert(newm.strhash_hit - oldm.strhash_hit == 1);<br>- assert(newm.strhash_miss - oldm.strhash_miss == 1);<br>- lua_pop(L, 3);<br>- lua_pushboolean(L, 1);<br>- return 1;<br>-}<br>-<br>-static int tracenum_base(lua_State *L)<br>-{<br>- struct luam_Metrics metrics;<br>- int n = lua_gettop(L);<br>- if (n != 1 || !lua_isfunction(L, 1))<br>- luaL_error(L, "incorrect arguments: 1 function is required");<br>-<br>- luaJIT_setmode(L, 0, LUAJIT_MODE_FLUSH);<br>- /* Force up garbage collect all dead objects. */<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>-<br>- luaM_metrics(L, &metrics);<br>- assert(metrics.jit_trace_num == 0);<br>-<br>- /* Generate traces. */<br>- lua_call(L, 0, 1);<br>- n = lua_gettop(L);<br>- if (n != 1 || !lua_isnumber(L, 1))<br>- luaL_error(L, "incorrect return value: 1 number is required");<br>- size_t jit_trace_num = lua_tonumber(L, 1);<br>- luaM_metrics(L, &metrics);<br>- assert(metrics.jit_trace_num == jit_trace_num);<br>-<br>- luaJIT_setmode(L, 0, LUAJIT_MODE_FLUSH);<br>- /* Force up garbage collect all dead objects. */<br>- lua_gc(L, LUA_GCCOLLECT, 0);<br>- luaM_metrics(L, &metrics);<br>- assert(metrics.jit_trace_num == 0);<br>-<br>- lua_pushboolean(L, 1);<br>- return 1;<br>-}<br>-<br>-static const struct luaL_Reg testgetmetrics[] = {<br>- {"base", base},<br>- {"gc_allocated_freed", gc_allocated_freed},<br>- {"gc_steps", gc_steps},<br>- {"objcount", objcount},<br>- {"objcount_cdata_decrement", objcount_cdata_decrement},<br>- {"snap_restores", snap_restores},<br>- {"strhash", strhash},<br>- {"tracenum_base", tracenum_base},<br>- {NULL, NULL}<br>-};<br>-<br>-LUA_API int luaopen_testgetmetrics(lua_State *L)<br>-{<br>- luaL_register(L, "testgetmetrics", testgetmetrics);<br>- return 1;<br>-}<br>--<br>2.34.1</div></div></div></div></blockquote><div><div>--<br>Best regards,</div><div>Maxim Kokryashkin</div></div><div> </div></div></blockquote></BODY></HTML>