From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id AEA764DD247; Wed, 7 Jun 2023 19:18:59 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org AEA764DD247 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1686154739; bh=rzwv5bze5Kqi51zpUkQXy6KyKe4eeI/dEMY3P2KMJes=; h=Date:To:Cc:References:In-Reply-To:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=BmNleEfQxUEYa+nx/Mv5Ifq5Yup5B4gz2/3W9mfPsNMqP80hxksYUJBZYEUp8cHOr uPPC+dsF37IN8pZajKE+/zLXCS26pdYJi2397EtRyixdc//6vKwD0+y3OnnRSa2931 hA7oBj8jxPAPHZwp7Q78CN8exDrD/+J1M6C3L/mk= Received: from smtp29.i.mail.ru (smtp29.i.mail.ru [95.163.41.68]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 069A64DD247 for ; Wed, 7 Jun 2023 19:18:59 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 069A64DD247 Received: by smtp29.i.mail.ru with esmtpa (envelope-from ) id 1q6vs9-004az2-P5; Wed, 07 Jun 2023 19:18:58 +0300 Message-ID: <3013bac0-eb92-ec51-f75d-14ca05c5b599@tarantool.org> Date: Wed, 7 Jun 2023 19:18:57 +0300 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.11.0 Content-Language: en-US To: Sergey Kaplun , Igor Munkin , Maxim Kokryashkin Cc: tarantool-patches@dev.tarantool.org References: In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD93D74B10BAB639DE36D2BB534DDE30F7B9C65136C4290857700894C459B0CD1B9B7EDDE58784ADF8E200E9A1F89D144654945AD34BC240EC129FF1465CC0F6BAA X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7D9C4478D0B876341EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637B35447D73BF3EFFE8638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D85E7744FC278443E93BB8A25772DF347D117882F4460429724CE54428C33FAD305F5C1EE8F4F765FC55D5BE2F85BDEC5FA471835C12D1D9774AD6D5ED66289B52BA9C0B312567BB23117882F44604297287769387670735204B6963042765DA4BCB629EEF1311BF91D2E47CDBA5A96583BA9C0B312567BB2376E601842F6C81A19E625A9149C048EE437C869540D2AB0F098B145E00970258D8FC6C240DEA7642DBF02ECDB25306B2B78CF848AE20165D0A6AB1C7CE11FEE32A336C65186350916E0066C2D8992A16C4224003CC836476E2F48590F00D11D6E2021AF6380DFAD1A18204E546F3947C2FFDA4F57982C5F42E808ACE2090B5E1725E5C173C3A84C3C5EA940A35A165FF2DBA43225CD8A89F83C798A30B85E16B5E1C53F199C2BB95B5C8C57E37DE458BEDA766A37F9254B7 X-B7AD71C0: 4965CFDFE0519134C1FE400A9E48C5401DD40DE57556AFB266D16FC5F53507A1816E0A2A8F779BBED8D40077074E805C66D16FC5F53507A117535B0CF9F6D0C3EE9D5CB6078CC77C4739C543750A29625FA128949B992996 X-C1DE0DAB: 0D63561A33F958A56588C1E8A6A7537A28AADB38A4CF884DF6254F6225B81666F87CCE6106E1FC07E67D4AC08A07B9B06A1CB4668A9CA5FACB5012B2E24CD356 X-C8649E89: 1C3962B70DF3F0AD75DCE07D45A749953FED46C3ACD6F73ED3581295AF09D3DF87807E0823442EA2ED31085941D9CD0AF7F820E7B07EA4CF695EECB0AA578DAAFF8DFC9649178FBB5D286AFE66BA8E30B04E536725142D4C0FDE042572883009588A46A5EBCE8E37798C30DFBE7A2039C6420E716B5D5E8CA74DFFEFA5DC0E7F02C26D483E81D6BE0DBAE6F56676BC7117BB6831D7356A2DEC5B5AD62611EEC62B5AFB4261A09AF0 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojC5OBK/dlsGOFQyhPg0dD7Q== X-Mailru-Sender: C4F68CFF4024C8867DFDF7C7F2588458A5965AB35C4F5FFD2DE32942F77C9F907EFD0D4E52B6CE39282EC151BADDC1D3523A6D01B4765B2DFB59E2DDD9FE06B14FA522850F29BC30B0DAF586E7D11B3E67EA787935ED9F1B X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH v3 luajit 5/6] test: rewrite misclib-sysprof-capi test in C X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Bronnikov via Tarantool-patches Reply-To: Sergey Bronnikov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Sergey, thanks for the patch! LGTM On 6/5/23 13:41, Sergey Kaplun wrote: > This patch rewrites the aforementioned test with the usage libtest > recently introduced. The approach is similar to the previous patch. > `c_payload()` function to profile is now set up globally on script > loading. The payload for enabled and disabled JIT is the same. As far as > for sysprof testing is necessary to replace backtrace with libunwind > first, the payload tests are marked with `todo()`. > > Nevertheless, glibc `assert()` still necessary to check the correctness > of the profile writer, so it is still used there. > > Relates to tarantool/tarantool#781 > Part of tarantool/tarantool#7900 > --- > .../misclib-sysprof-capi-script.lua | 35 ++ > .../misclib-sysprof-capi.test.c | 325 ++++++++++++++++++ > test/tarantool-tests/CMakeLists.txt | 1 - > .../misclib-sysprof-capi.test.lua | 54 --- > .../misclib-sysprof-capi/CMakeLists.txt | 1 - > .../misclib-sysprof-capi/testsysprof.c | 260 -------------- > 6 files changed, 360 insertions(+), 316 deletions(-) > create mode 100644 test/tarantool-c-tests/misclib-sysprof-capi-script.lua > create mode 100644 test/tarantool-c-tests/misclib-sysprof-capi.test.c > delete mode 100644 test/tarantool-tests/misclib-sysprof-capi.test.lua > delete mode 100644 test/tarantool-tests/misclib-sysprof-capi/CMakeLists.txt > delete mode 100644 test/tarantool-tests/misclib-sysprof-capi/testsysprof.c > > diff --git a/test/tarantool-c-tests/misclib-sysprof-capi-script.lua b/test/tarantool-c-tests/misclib-sysprof-capi-script.lua > new file mode 100644 > index 00000000..dd8387db > --- /dev/null > +++ b/test/tarantool-c-tests/misclib-sysprof-capi-script.lua > @@ -0,0 +1,35 @@ > +local M = {} > + > +-- luacheck: no global > +assert(c_payload, 'c_payload global function should be set via script loader') > + > +local function lua_payload(n) > + if n <= 1 then > + return n > + end > + return lua_payload(n - 1) + lua_payload(n - 2) > +end > + > +local function payload() > + local n_iterations = 500000 > + > + local co = coroutine.create(function() > + for i = 1, n_iterations do > + if i % 2 == 0 then > + c_payload(10) > + else > + lua_payload(10) > + end > + coroutine.yield() > + end > + end) > + > + for _ = 1, n_iterations do > + coroutine.resume(co) > + end > +end > + > +M.profile_func_jiton = payload > +M.profile_func_jitoff = payload > + > +return M > diff --git a/test/tarantool-c-tests/misclib-sysprof-capi.test.c b/test/tarantool-c-tests/misclib-sysprof-capi.test.c > new file mode 100644 > index 00000000..4a7a0d46 > --- /dev/null > +++ b/test/tarantool-c-tests/misclib-sysprof-capi.test.c > @@ -0,0 +1,325 @@ > +#include "lauxlib.h" > +#include "lmisclib.h" > +#include "lua.h" > +#include "luajit.h" > + > +#include "test.h" > +#include "utils.h" > + > +#include > +#include > +#include > +#include > + > +/* XXX: Still need normal assert inside writer functions. */ > +#undef NDEBUG > +#include > + > +/* Need for skipcond for OS and ARCH. */ > +#include "lj_arch.h" > + > +#define UNUSED(x) ((void)(x)) > + > +/* --- utils -------------------------------------------------- */ > + > +#define SYSPROF_INTERVAL_DEFAULT 100 > + > +/* > + * Yep, 8Mb. Tuned in order not to bother the platform with too > + * often flushes. > + */ > +#define STREAM_BUFFER_SIZE (8 * 1024 * 1024) > + > + > +/* --- C Payload ---------------------------------------------- */ > + > +static double fib(double n) > +{ > + if (n <= 1) > + return n; > + return fib(n - 1) + fib(n - 2); > +} > + > +static int c_payload(lua_State *L) > +{ > + fib(luaL_checknumber(L, 1)); > + lua_pushboolean(L, 1); > + return 1; > +} > +/* --- sysprof C API tests ------------------------------------ */ > + > +static int base(void *test_state) > +{ > + UNUSED(test_state); > + struct luam_Sysprof_Options opt = {}; > + struct luam_Sysprof_Counters cnt = {}; > + > + (void)opt.interval; > + (void)opt.mode; > + (void)opt.ctx; > + (void)opt.buf; > + (void)opt.len; > + > + luaM_sysprof_report(&cnt); > + > + (void)cnt.samples; > + (void)cnt.vmst_interp; > + (void)cnt.vmst_lfunc; > + (void)cnt.vmst_ffunc; > + (void)cnt.vmst_cfunc; > + (void)cnt.vmst_gc; > + (void)cnt.vmst_exit; > + (void)cnt.vmst_record; > + (void)cnt.vmst_opt; > + (void)cnt.vmst_asm; > + (void)cnt.vmst_trace; > + > + return TEST_EXIT_SUCCESS; > +} > + > +static int validation(void *test_state) > +{ > + lua_State *L = test_state; > + struct luam_Sysprof_Options opt = {}; > + int status = PROFILE_SUCCESS; > + > + /* Unknown mode. */ > + opt.mode = 0x40; > + status = luaM_sysprof_start(L, &opt); > + assert_true(status == PROFILE_ERRUSE); > + > + /* Buffer not configured. */ > + opt.mode = LUAM_SYSPROF_CALLGRAPH; > + opt.buf = NULL; > + status = luaM_sysprof_start(L, &opt); > + assert_true(status == PROFILE_ERRUSE); > + > + /* Bad interval. */ > + opt.mode = LUAM_SYSPROF_DEFAULT; > + opt.interval = 0; > + status = luaM_sysprof_start(L, &opt); > + assert_true(status == PROFILE_ERRUSE); > + > + /* Check if profiling started. */ > + opt.mode = LUAM_SYSPROF_DEFAULT; > + opt.interval = SYSPROF_INTERVAL_DEFAULT; > + status = luaM_sysprof_start(L, &opt); > + assert_true(status == PROFILE_SUCCESS); > + > + /* Already running. */ > + status = luaM_sysprof_start(L, &opt); > + assert_true(status == PROFILE_ERRRUN); > + > + /* Profiler stopping. */ > + status = luaM_sysprof_stop(L); > + assert_true(status == PROFILE_SUCCESS); > + > + /* Stopping profiler which is not running. */ > + status = luaM_sysprof_stop(L); > + assert_true(status == PROFILE_ERRRUN); > + > + return TEST_EXIT_SUCCESS; > +} > + > +/* > + * FIXME: The following two tests are disabled because sometimes > + * `backtrace` dynamically loads a platform-specific unwinder, > + * which is not signal-safe. > + */ > + > +#if 0 > +/* > + * Structure given as ctx to sysprof writer and on_stop callback. > + */ > +struct sysprof_ctx { > + /* Output file descriptor for data. */ > + int fd; > + /* Buffer for data. */ > + uint8_t buf[STREAM_BUFFER_SIZE]; > +}; > + > +/* > + * Default buffer writer function. > + * Just call fwrite to the corresponding FILE. > + */ > +static size_t buffer_writer_default(const void **buf_addr, size_t len, > + void *opt) > +{ > + struct sysprof_ctx *ctx = opt; > + int fd = ctx->fd; > + const void * const buf_start = *buf_addr; > + const void *data = *buf_addr; > + size_t write_total = 0; > + > + assert(len <= STREAM_BUFFER_SIZE); > + > + for (;;) { > + const size_t written = write(fd, data, len - write_total); > + > + if (written == 0) { > + /* Re-tries write in case of EINTR. */ > + if (errno != EINTR) { > + /* > + * Will be freed as whole chunk > + * later. > + */ > + *buf_addr = NULL; > + return write_total; > + } > + errno = 0; > + continue; > + } > + > + write_total += written; > + assert(write_total <= len); > + > + if (write_total == len) > + break; > + > + data = (uint8_t *)data + (ptrdiff_t)written; > + } > + > + *buf_addr = buf_start; > + return write_total; > +} > + > +/* > + * Default on stop callback. Just close the corresponding stream. > + */ > +static int on_stop_cb_default(void *opt, uint8_t *buf) > +{ > + UNUSED(buf); > + struct sysprof_ctx *ctx = opt; > + int fd = ctx->fd; > + free(ctx); > + return close(fd); > +} > + > +static int stream_init(struct luam_Sysprof_Options *opt) > +{ > + struct sysprof_ctx *ctx = calloc(1, sizeof(struct sysprof_ctx)); > + if (NULL == ctx) > + return PROFILE_ERRIO; > + > + ctx->fd = open("/dev/null", O_WRONLY | O_CREAT, 0644); > + if (-1 == ctx->fd) { > + free(ctx); > + return PROFILE_ERRIO; > + } > + > + opt->ctx = ctx; > + opt->buf = ctx->buf; > + opt->len = STREAM_BUFFER_SIZE; > + > + return PROFILE_SUCCESS; > +} > + > +/* Get function to profile on top, call it. */ > +static int check_profile_func(lua_State *L) > +{ > + struct luam_Sysprof_Options opt = {}; > + struct luam_Sysprof_Counters cnt = {}; > + int status = PROFILE_ERRUSE; > + /* > + * Since all the other modes functionality is the > + * subset of CALLGRAPH mode, run this mode to test > + * the profiler's behavior. > + */ > + opt.mode = LUAM_SYSPROF_CALLGRAPH; > + opt.interval = SYSPROF_INTERVAL_DEFAULT; > + stream_init(&opt); > + > + /* > + * XXX: Payload function on top will not be removed if any > + * of those assertions fail. So, the next call to the > + * `utils_get_aux_lfunc()` will fail. It's OK, since > + * we are already in trouble, just keep it in mind. > + */ > + assert_true(luaM_sysprof_set_writer(buffer_writer_default) > + == PROFILE_SUCCESS); > + assert_true(luaM_sysprof_set_on_stop(on_stop_cb_default) > + == PROFILE_SUCCESS); > + assert_true(luaM_sysprof_set_backtracer(NULL) == PROFILE_SUCCESS); > + > + status = luaM_sysprof_start(L, &opt); > + assert_true(status == PROFILE_SUCCESS); > + > + /* Run payload. */ > + if (lua_pcall(L, 0, 0, 0) != LUA_OK) { > + test_comment("error running payload: %s", lua_tostring(L, -1)); > + bail_out("error running sysprof test payload"); > + } > + > + status = luaM_sysprof_stop(L); > + assert_true(status == PROFILE_SUCCESS); > + > + status = luaM_sysprof_report(&cnt); > + assert_true(status == PROFILE_SUCCESS); > + > + assert_true(cnt.samples > 1); > + assert_true(cnt.samples == cnt.vmst_asm + > + cnt.vmst_cfunc + > + cnt.vmst_exit + > + cnt.vmst_ffunc + > + cnt.vmst_gc + > + cnt.vmst_interp + > + cnt.vmst_lfunc + > + cnt.vmst_opt + > + cnt.vmst_record + > + cnt.vmst_trace); > + > + return TEST_EXIT_SUCCESS; > +} > +#endif > + > +static int profile_func_jitoff(void *test_state) > +{ > + UNUSED(test_state); > + return todo("Need to replace backtrace with libunwind first"); > +#if 0 > + lua_State *L = test_state; > + utils_get_aux_lfunc(L); > + (void)luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_OFF); > + (void)luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_FLUSH); > + check_profile_func(L); > + (void)luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_ON); > + return TEST_EXIT_SUCCESS; > +#endif > +} > + > +static int profile_func_jiton(void *test_state) > +{ > + UNUSED(test_state); > + return todo("Need to replace backtrace with libunwind first"); > +#if 0 > + lua_State *L = test_state; > + utils_get_aux_lfunc(L); > + check_profile_func(L); > + return TEST_EXIT_SUCCESS; > +#endif > +} > + > +int main(void) > +{ > + if (LUAJIT_OS != LUAJIT_OS_LINUX) > + return skip_all("Sysprof is implemented for Linux only"); > + if (LUAJIT_TARGET != LUAJIT_ARCH_X86 > + && LUAJIT_TARGET != LUAJIT_ARCH_X64) > + return skip_all("Sysprof is implemented for x86_64 only"); > + > + lua_State *L = utils_lua_init(); > + > + lua_pushcfunction(L, c_payload); > + lua_setfield(L, LUA_GLOBALSINDEX, "c_payload"); > + utils_load_aux_script(L, "misclib-sysprof-capi-script.lua"); > + > + const struct test_unit tgroup[] = { > + test_unit_new(base), > + test_unit_new(validation), > + test_unit_new(profile_func_jitoff), > + test_unit_new(profile_func_jiton) > + }; > + 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 b4ce39d3..b1c7207f 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-sysprof-capi) > > # The part of the memory profiler toolchain is located in tools > # directory, jit, profiler, and bytecode toolchains are located > diff --git a/test/tarantool-tests/misclib-sysprof-capi.test.lua b/test/tarantool-tests/misclib-sysprof-capi.test.lua > deleted file mode 100644 > index 4395bce3..00000000 > --- a/test/tarantool-tests/misclib-sysprof-capi.test.lua > +++ /dev/null > @@ -1,54 +0,0 @@ > -local tap = require("tap") > -local test = tap.test("clib-misc-sysprof"):skipcond({ > - ["Sysprof is implemented for x86_64 only"] = jit.arch ~= "x86" and > - jit.arch ~= "x64", > - ["Sysprof is implemented for Linux only"] = jit.os ~= "Linux", > -}) > - > -test:plan(2) > - > -local testsysprof = require("testsysprof") > - > -jit.off() > - > -test:ok(testsysprof.base()) > -test:ok(testsysprof.validation()) > - > --- FIXME: The following two tests are disabled because sometimes > --- `backtrace` dynamically loads a platform-specific unwinder, which is > --- not signal-safe. > ---[[ > -local function lua_payload(n) > - if n <= 1 then > - return n > - end > - return lua_payload(n - 1) + lua_payload(n - 2) > -end > - > -local function payload() > - local n_iterations = 500000 > - > - local co = coroutine.create(function () > - for i = 1, n_iterations do > - if i % 2 == 0 then > - testsysprof.c_payload(10) > - else > - lua_payload(10) > - end > - coroutine.yield() > - end > - end) > - > - for _ = 1, n_iterations do > - coroutine.resume(co) > - end > -end > - > -test:ok(testsysprof.profile_func(payload)) > - > -jit.on() > -jit.flush() > - > -test:ok(testsysprof.profile_func(payload)) > ---]] > -os.exit(test:check() and 0 or 1) > diff --git a/test/tarantool-tests/misclib-sysprof-capi/CMakeLists.txt b/test/tarantool-tests/misclib-sysprof-capi/CMakeLists.txt > deleted file mode 100644 > index d9fb1a1a..00000000 > --- a/test/tarantool-tests/misclib-sysprof-capi/CMakeLists.txt > +++ /dev/null > @@ -1 +0,0 @@ > -BuildTestCLib(testsysprof testsysprof.c) > diff --git a/test/tarantool-tests/misclib-sysprof-capi/testsysprof.c b/test/tarantool-tests/misclib-sysprof-capi/testsysprof.c > deleted file mode 100644 > index d7a3e355..00000000 > --- a/test/tarantool-tests/misclib-sysprof-capi/testsysprof.c > +++ /dev/null > @@ -1,260 +0,0 @@ > -#include > -#include > -#include > - > -#include > - > -#include > -#include > -#include > -#include > - > -#undef NDEBUG > -#include > - > -#define UNUSED(x) ((void)(x)) > - > -/* --- utils -------------------------------------------------------------- */ > - > -#define SYSPROF_INTERVAL_DEFAULT 100 > - > -/* > - ** Yep, 8Mb. Tuned in order not to bother the platform with too often flushes. > - */ > -#define STREAM_BUFFER_SIZE (8 * 1024 * 1024) > - > -/* Structure given as ctx to sysprof writer and on_stop callback. */ > -struct sysprof_ctx { > - /* Output file descriptor for data. */ > - int fd; > - /* Buffer for data. */ > - uint8_t buf[STREAM_BUFFER_SIZE]; > -}; > - > -/* > - ** Default buffer writer function. > - ** Just call fwrite to the corresponding FILE. > - */ > -static size_t buffer_writer_default(const void **buf_addr, size_t len, > - void *opt) > -{ > - struct sysprof_ctx *ctx = opt; > - int fd = ctx->fd; > - const void * const buf_start = *buf_addr; > - const void *data = *buf_addr; > - size_t write_total = 0; > - > - assert(len <= STREAM_BUFFER_SIZE); > - > - for (;;) { > - const size_t written = write(fd, data, len - write_total); > - > - if (written == 0) { > - /* Re-tries write in case of EINTR. */ > - if (errno != EINTR) { > - /* Will be freed as whole chunk later. */ > - *buf_addr = NULL; > - return write_total; > - } > - errno = 0; > - continue; > - } > - > - write_total += written; > - assert(write_total <= len); > - > - if (write_total == len) > - break; > - > - data = (uint8_t *)data + (ptrdiff_t)written; > - } > - > - *buf_addr = buf_start; > - return write_total; > -} > - > -/* Default on stop callback. Just close the corresponding stream. */ > -static int on_stop_cb_default(void *opt, uint8_t *buf) > -{ > - UNUSED(buf); > - struct sysprof_ctx *ctx = opt; > - int fd = ctx->fd; > - free(ctx); > - return close(fd); > -} > - > -static int stream_init(struct luam_Sysprof_Options *opt) > -{ > - struct sysprof_ctx *ctx = calloc(1, sizeof(struct sysprof_ctx)); > - if (NULL == ctx) > - return PROFILE_ERRIO; > - > - ctx->fd = open("/dev/null", O_WRONLY | O_CREAT, 0644); > - if (-1 == ctx->fd) { > - free(ctx); > - return PROFILE_ERRIO; > - } > - > - opt->ctx = ctx; > - opt->buf = ctx->buf; > - opt->len = STREAM_BUFFER_SIZE; > - > - return PROFILE_SUCCESS; > -} > - > -/* --- Payload ------------------------------------------------------------ */ > - > -static double fib(double n) > -{ > - if (n <= 1) > - return n; > - return fib(n - 1) + fib(n - 2); > -} > - > -static int c_payload(lua_State *L) > -{ > - fib(luaL_checknumber(L, 1)); > - lua_pushboolean(L, 1); > - return 1; > -} > - > -/* --- sysprof C API tests ------------------------------------------------ */ > - > -static int base(lua_State *L) > -{ > - struct luam_Sysprof_Options opt = {}; > - struct luam_Sysprof_Counters cnt = {}; > - > - (void)opt.interval; > - (void)opt.mode; > - (void)opt.ctx; > - (void)opt.buf; > - (void)opt.len; > - > - luaM_sysprof_report(&cnt); > - > - (void)cnt.samples; > - (void)cnt.vmst_interp; > - (void)cnt.vmst_lfunc; > - (void)cnt.vmst_ffunc; > - (void)cnt.vmst_cfunc; > - (void)cnt.vmst_gc; > - (void)cnt.vmst_exit; > - (void)cnt.vmst_record; > - (void)cnt.vmst_opt; > - (void)cnt.vmst_asm; > - (void)cnt.vmst_trace; > - > - lua_pushboolean(L, 1); > - return 1; > -} > - > -static int validation(lua_State *L) > -{ > - struct luam_Sysprof_Options opt = {}; > - int status = PROFILE_SUCCESS; > - > - /* Unknown mode. */ > - opt.mode = 0x40; > - status = luaM_sysprof_start(L, &opt); > - assert(PROFILE_ERRUSE == status); > - > - /* Buffer not configured. */ > - opt.mode = LUAM_SYSPROF_CALLGRAPH; > - opt.buf = NULL; > - status = luaM_sysprof_start(L, &opt); > - assert(PROFILE_ERRUSE == status); > - > - /* Bad interval. */ > - opt.mode = LUAM_SYSPROF_DEFAULT; > - opt.interval = 0; > - status = luaM_sysprof_start(L, &opt); > - assert(PROFILE_ERRUSE == status); > - > - /* Check if profiling started. */ > - opt.mode = LUAM_SYSPROF_DEFAULT; > - opt.interval = SYSPROF_INTERVAL_DEFAULT; > - status = luaM_sysprof_start(L, &opt); > - assert(PROFILE_SUCCESS == status); > - > - /* Already running. */ > - status = luaM_sysprof_start(L, &opt); > - assert(PROFILE_ERRRUN == status); > - > - /* Profiler stopping. */ > - status = luaM_sysprof_stop(L); > - assert(PROFILE_SUCCESS == status); > - > - /* Stopping profiler which is not running. */ > - status = luaM_sysprof_stop(L); > - assert(PROFILE_ERRRUN == status); > - > - lua_pushboolean(L, 1); > - return 1; > -} > - > -static int profile_func(lua_State *L) > -{ > - struct luam_Sysprof_Options opt = {}; > - struct luam_Sysprof_Counters cnt = {}; > - int status = PROFILE_ERRUSE; > - > - int n = lua_gettop(L); > - if (n != 1 || !lua_isfunction(L, 1)) > - luaL_error(L, "incorrect argument: 1 function is required"); > - > - /* > - ** Since all the other modes functionality is the > - ** subset of CALLGRAPH mode, run this mode to test > - ** the profiler's behavior. > - */ > - opt.mode = LUAM_SYSPROF_CALLGRAPH; > - opt.interval = SYSPROF_INTERVAL_DEFAULT; > - stream_init(&opt); > - > - assert(luaM_sysprof_set_writer(buffer_writer_default) == PROFILE_SUCCESS); > - assert(luaM_sysprof_set_on_stop(on_stop_cb_default) == PROFILE_SUCCESS); > - assert(luaM_sysprof_set_backtracer(NULL) == PROFILE_SUCCESS); > - > - status = luaM_sysprof_start(L, &opt); > - assert(PROFILE_SUCCESS == status); > - > - /* Run payload. */ > - if (lua_pcall(L, 0, 0, 0) != LUA_OK) > - luaL_error(L, "error running payload: %s", lua_tostring(L, -1)); > - > - status = luaM_sysprof_stop(L); > - assert(PROFILE_SUCCESS == status); > - > - status = luaM_sysprof_report(&cnt); > - assert(PROFILE_SUCCESS == status); > - > - assert(cnt.samples > 1); > - assert(cnt.samples == cnt.vmst_asm + > - cnt.vmst_cfunc + > - cnt.vmst_exit + > - cnt.vmst_ffunc + > - cnt.vmst_gc + > - cnt.vmst_interp + > - cnt.vmst_lfunc + > - cnt.vmst_opt + > - cnt.vmst_record + > - cnt.vmst_trace); > - > - lua_pushboolean(L, 1); > - return 1; > -} > - > -static const struct luaL_Reg testsysprof[] = { > - {"base", base}, > - {"c_payload", c_payload}, > - {"profile_func", profile_func}, > - {"validation", validation}, > - {NULL, NULL} > -}; > - > -LUA_API int luaopen_testsysprof(lua_State *L) > -{ > - luaL_register(L, "testsysprof", testsysprof); > - return 1; > -}