--- /dev/null
+--[[ https://en.wikipedia.org/wiki/Normal_distribution ]]
+
+-- The Box–Muller method
+local function gaussian(mean, variance)
+ local U = math.random()
+ local V = math.random()
+ return math.sqrt(-2.0 * variance * math.log(U)) *
+ math.cos(2.0 * math.pi * V) + mean
+end
+
+local function mean(t)
+ local sum = 0
+ local count = #t
+ for i = 1, count do
+ sum = sum + t[i]
+ end
+ return sum / count
+end
+
+local function std(t, mean)
+ local squares = 0.0
+ for i = 1, #t do
+ local deviation = math.abs(mean - t[i])
+ squares = squares + deviation * deviation
+ end
+ local variance = squares / #t
+ return math.sqrt(variance)
+end
+
+local function do_the_call()
+ local t = {}
+ local mu = 34.0
+ local sigma = 10.0
+
+ for i = 1, 5 do
+ table.insert(t, gaussian(mu, sigma))
+ end
+
+ return string.format("Got mean: %1.5f, mu: %1.5f\nstd deviance:%1.5f, expected: %1.5f",
+ mean(t), mu,
+ std(t, mu), math.sqrt(sigma))
+end
+
+math.randomseed(os.time())
+return do_the_call
--- /dev/null
+/*-
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "rspamd.h"
+#include "util.h"
+#include "lua/lua_common.h"
+#include "lua/lua_thread_pool.h"
+#include "unix-std.h"
+
+static const char *lua_src = BUILDROOT "/test/lua/pcall_test.lua";
+
+extern struct rspamd_main *rspamd_main;
+
+const int N = 20000;
+
+
+static gdouble
+test_pcall(lua_State *L, gint function_call)
+{
+ gdouble t1, t2;
+ gint i;
+ t1 = rspamd_get_virtual_ticks ();
+
+ for (i = 0; i < N; i ++) {
+ lua_rawgeti (L, LUA_REGISTRYINDEX, function_call);
+ lua_pcall (L, 0, 1, 0);
+ lua_pop (L, 1);
+ }
+
+ t2 = rspamd_get_virtual_ticks ();
+
+ return t2 - t1;
+}
+
+static gdouble
+test_resume(lua_State *L, gint function_call)
+{
+ gdouble t1, t2;
+ gint i;
+ t1 = rspamd_get_virtual_ticks ();
+
+ for (i = 0; i < N; i ++) {
+ lua_rawgeti (L, LUA_REGISTRYINDEX, function_call);
+ lua_resume (L, 0);
+ lua_pop (L, 1);
+ }
+
+ t2 = rspamd_get_virtual_ticks ();
+
+ return t2 - t1;
+}
+
+static gdouble
+test_resume_get_thread(gint function_call)
+{
+ gdouble t1, t2;
+ gint i;
+ struct thread_entry *ent;
+
+ t1 = rspamd_get_virtual_ticks ();
+
+ for (i = 0; i < N; i ++) {
+ ent = lua_thread_pool_get (rspamd_main->cfg->lua_thread_pool);
+
+ lua_rawgeti (ent->lua_state, LUA_REGISTRYINDEX, function_call);
+ lua_resume (ent->lua_state, 0);
+ lua_pop (ent->lua_state, 1);
+
+ lua_thread_pool_return (rspamd_main->cfg->lua_thread_pool, ent);
+ }
+
+ t2 = rspamd_get_virtual_ticks ();
+
+ return t2 - t1;
+}
+
+static gdouble
+test_resume_get_new_thread(gint function_call)
+{
+ gdouble t1, t2;
+ gint i;
+ struct thread_entry *ent;
+
+ t1 = rspamd_get_virtual_ticks ();
+
+ for (i = 0; i < N; i ++) {
+ ent = lua_thread_pool_get (rspamd_main->cfg->lua_thread_pool);
+
+ lua_rawgeti (ent->lua_state, LUA_REGISTRYINDEX, function_call);
+ lua_resume (ent->lua_state, 0);
+ lua_pop (ent->lua_state, 1);
+
+ /* lua_thread_pool_return (rspamd_main->cfg->lua_thread_pool, ent); */
+ }
+
+ t2 = rspamd_get_virtual_ticks ();
+
+ return t2 - t1;
+}
+
+void
+rspamd_lua_lua_pcall_vs_resume_test_func (void)
+{
+ lua_State *L = rspamd_main->cfg->lua_state;
+ gdouble t1, reference;
+
+ if (luaL_dofile (L, lua_src) != 0) {
+ msg_err ("failed to load test file: %s ", lua_tostring (L, -1));
+ g_assert (0);
+ }
+
+ gint function_call = luaL_ref (L, LUA_REGISTRYINDEX);
+
+ msg_info ("calling");
+
+ reference = t1 = test_pcall(L, function_call);
+ msg_notice ("pcall stat: ts: %1.5f, avg:%1.5f, slow=%1.2f", t1, t1/(gdouble)N, t1 / reference);
+
+ t1 = test_resume (L, function_call);
+ msg_notice ("resume stat: ts: %1.5f, avg:%1.5f, slow=%1.2f", t1, t1/(gdouble)N, t1 / reference);
+
+ t1 = test_resume_get_thread (function_call);
+ msg_notice ("resume+get thread stat: ts: %1.5f, avg:%1.5f, slow=%1.2f", t1, t1/(gdouble)N, t1 / reference);
+
+ t1 = test_resume_get_new_thread (function_call);
+ msg_notice ("resume+get [new] thread stat: ts: %1.5f, avg:%1.5f, slow=%1.2f", t1, t1/(gdouble)N, t1 / reference);
+}
\ No newline at end of file