From e5ac4d3d9ef37440d563b6f80610eafa157462d3 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Mon, 24 Oct 2022 23:24:24 -0400 Subject: [PATCH] Testing new optimization features --- multi/init.lua | 164 +++++++++++++++++- multi/integration/lanesManager/extensions.lua | 7 +- multi/integration/lanesManager/init.lua | 2 + test.lua | 135 +++++++------- 4 files changed, 230 insertions(+), 78 deletions(-) diff --git a/multi/init.lua b/multi/init.lua index 4b7aab6..bab2b39 100644 --- a/multi/init.lua +++ b/multi/init.lua @@ -29,6 +29,7 @@ local clock = os.clock local thread = {} local in_proc = false local processes = {} +local find_optimization = false if not _G["$multi"] then _G["$multi"] = {multi=multi,thread=thread} @@ -113,7 +114,11 @@ end function multi.ForEach(tab,func) for i=1,#tab do func(tab[i]) end end +local CRef = { + Fire = function() end +} +local optimization_stats = {} local ignoreconn = true function multi:newConnection(protect,func,kill) local c={} @@ -128,8 +133,11 @@ function multi:newConnection(protect,func,kill) for i,v in pairs(t) do if v==self then local ref = self:Connect(select(2,...)) - ref.root_link = select(1,...) - return ref + if ref then + ref.root_link = select(1,...) + return ref + end + return self end end return self:Connect(...) @@ -207,7 +215,10 @@ function multi:newConnection(protect,func,kill) if lock then return end for i=#call_funcs,1,-1 do if not call_funcs[i] then return end - pcall(call_funcs[i],...) + local suc, err = pcall(call_funcs[i],...) + if not suc then + print(err) + end if kill then table.remove(call_funcs,i) end @@ -231,6 +242,7 @@ function multi:newConnection(protect,func,kill) end function c:fastMode() + if find_optimization then return self end function self:Fire(...) for i=1,#fast do fast[i](...) @@ -341,16 +353,39 @@ function multi:newConnection(protect,func,kill) return self end + if find_optimization then + -- + end + c.connect=c.Connect c.GetConnection=c.getConnection c.HasConnections = c.hasConnections c.GetConnection = c.getConnection + if not(ignoreconn) then multi:create(c) end return c end +multi.enableOptimization = multi:newConnection() +multi.optConn = multi:newConnection(true) +multi.optConn(function(msg) + table.insert(optimization_stats, msg) +end) + +function multi:getOptimizationConnection() + return multi.optConn +end + +function multi:getOptimizationStats() + return optimization_stats +end + +function multi:isFindingOptimizing() + return find_optimization +end + -- Used with ISO Threads local function isolateFunction(func,env) local dmp = string.dump(func) @@ -531,10 +566,6 @@ function multi:newConnector() return c end -local CRef = { - Fire = function() end -} - multi.OnObjectCreated=multi:newConnection() multi.OnObjectDestroyed=multi:newConnection() multi.OnLoad = multi:newConnection(nil,nil,true) @@ -1093,6 +1124,62 @@ function thread.hold(n,opt) end end +function thread.hold(n,opt) + thread._Requests() + local opt = opt or {} + if type(opt)=="table" then + interval = opt.interval + if opt.cycles then + return yield(CMD, t_holdW, opt.cycles or 1, n or dFunc, interval) + elseif opt.sleep then + return yield(CMD, t_holdF, opt.sleep, n or dFunc, interval) + elseif opt.skip then + return yield(CMD, t_skip, opt.skip or 1, nil, interval) + end + end + + if type(n) == "number" then + thread.getRunningThread().lastSleep = clock() + return yield(CMD, t_sleep, n or 0, nil, interval) + elseif type(n) == "table" and n.Type == "connector" then + local rdy = function() + return false + end + n(function(a1,a2,a3,a4,a5,a6) + rdy = function() + if a1==nil then + return NIL,a2,a3,a4,a5,a6 + end + return a1,a2,a3,a4,a5,a6 + end + end) + return yield(CMD, t_hold, function() + return rdy() + end, nil, interval) + elseif type(n) == "function" then + if find_optimization then + local cache = string.dump(n) + local f_str = tostring(n) + local good = true + for i=1,#func_cache do + if func_cache[i][1] == cache and func_cache[i][2] ~= f_str then + if not func_cache[i][3] then + multi.optConn:Fire("It's better to store a function to a variable than to use an anonymous function within the hold method!\n" .. debug.traceback()) + func_cache[i][3] = true + end + good = false + end + end + if good then + table.insert(func_cache, {cache, f_str}) + end + end + return yield(CMD, t_hold, n or dFunc, nil, interval) + else + error("Invalid argument passed to thread.hold(...)!") + end +end + function thread.holdFor(sec,n) thread._Requests() return yield(CMD, t_holdF, sec, n or dFunc) @@ -1744,6 +1831,10 @@ function multi.init(settings, realsettings) else multi.mainloop = mainloop end + if settings.findopt then + find_optimization = true + multi.enableOptimization:Fire(multi, thread) + end end return _G["$multi"].multi,_G["$multi"].thread end @@ -2093,5 +2184,64 @@ else multi.m.sentinel = newproxy(true) getmetatable(multi.m.sentinel).__gc = multi.m.onexit end +local func_cache = {} +multi:newThread(function() + thread.skip() + if find_optimization then + + function thread.hold(n,opt) + thread._Requests() + local opt = opt or {} + if type(opt)=="table" then + interval = opt.interval + if opt.cycles then + return yield(CMD, t_holdW, opt.cycles or 1, n or dFunc, interval) + elseif opt.sleep then + return yield(CMD, t_holdF, opt.sleep, n or dFunc, interval) + elseif opt.skip then + return yield(CMD, t_skip, opt.skip or 1, nil, interval) + end + end + + if type(n) == "number" then + thread.getRunningThread().lastSleep = clock() + return yield(CMD, t_sleep, n or 0, nil, interval) + elseif type(n) == "table" and n.Type == "connector" then + local rdy = function() + return false + end + n(function(a1,a2,a3,a4,a5,a6) + rdy = function() + if a1==nil then + return NIL,a2,a3,a4,a5,a6 + end + return a1,a2,a3,a4,a5,a6 + end + end) + return yield(CMD, t_hold, function() + return rdy() + end, nil, interval) + elseif type(n) == "function" then + local cache = string.dump(n) + local f_str = tostring(n) + local good = true + for i=1,#func_cache do + if func_cache[i][1] == cache and func_cache[i][2] ~= f_str and not func_cache[i][3] then + multi:getOptimizationConnection():Fire("It's better to store a function to a variable than to use an anonymous function within the hold method!\n" .. debug.traceback()) + func_cache[i][3] = true + good = false + end + end + if good then + table.insert(func_cache, {cache, f_str}) + end + return yield(CMD, t_hold, n or dFunc, nil, interval) + else + error("Invalid argument passed to thread.hold(...)!") + end + end + -- Add more Overrides + end +end).OnError(print) return multi \ No newline at end of file diff --git a/multi/integration/lanesManager/extensions.lua b/multi/integration/lanesManager/extensions.lua index fdf9f9a..4fc7b93 100644 --- a/multi/integration/lanesManager/extensions.lua +++ b/multi/integration/lanesManager/extensions.lua @@ -239,13 +239,14 @@ function multi:newSystemThreadedConnection(name) thread:newThread("STC_SUB_MAN"..name,function() local item + local sub_func = function() -- This will keep things held up until there is something to process + return c.subscribe:pop() + end while true do thread.yield() -- We need to check on broken connections ping(c) -- Should return instantlly and process this in another thread - item = thread.hold(function() -- This will keep things held up until there is something to process - return c.subscribe:pop() - end) + item = thread.hold(sub_func) if item[1] == c.CONN then multi.ForEach(c.links, function(link) -- Sync new connections item[2]:push{c.CONN, link} diff --git a/multi/integration/lanesManager/init.lua b/multi/integration/lanesManager/init.lua index 26ac65c..b5a772b 100644 --- a/multi/integration/lanesManager/init.lua +++ b/multi/integration/lanesManager/init.lua @@ -77,6 +77,7 @@ function multi:newSystemThread(name, func, ...) c.creationTime = os.clock() c.alive = true c.priority = THREAD.Priority_Normal + local multi_settings = multi.defaultSettings c.thread = lanes.gen("*", { globals={ -- Set up some globals @@ -88,6 +89,7 @@ function multi:newSystemThread(name, func, ...) }, priority=c.priority },function(...) + require("multi"):init(multi_settings) require("multi.integration.lanesManager.extensions") local has_error = true return_linda:set("returns",{func(...)}) diff --git a/test.lua b/test.lua index f9e93e6..663a4c8 100644 --- a/test.lua +++ b/test.lua @@ -1,8 +1,10 @@ package.path = "./?/init.lua;?.lua;lua5.4/share/lua/5.4/?/init.lua;lua5.4/share/lua/5.4/?.lua;"--..package.path package.cpath = "lua5.4/lib/lua/5.4/?/core.dll;"--..package.cpath multi, thread = require("multi"):init{print=true} --- GLOBAL, THREAD = require("multi.integration.lanesManager"):init() - +GLOBAL, THREAD = require("multi.integration.lanesManager"):init() +multi:getOptimizationConnection()(function(msg) + print(msg) +end) -- local conn1, conn2, conn3 = multi:newConnection(), multi:newConnection(), multi:newConnection() -- thread:newThread(function() -- print("Awaiting status") @@ -23,77 +25,74 @@ multi, thread = require("multi"):init{print=true} -- conn3:Fire() -- end) +local conn = multi:newSystemThreadedConnection("conn"):init() +multi:newSystemThread("Thread_Test_1", function() + local multi, thread = require("multi"):init() + local conn = GLOBAL["conn"]:init() + local console = THREAD.getConsole() + conn(function(a,b,c) + console.print(THREAD:getName().." was triggered!",a,b,c) + end) + multi:mainloop() +end) +multi:newSystemThread("Thread_Test_2", function() + local multi, thread = require("multi"):init() + local conn = GLOBAL["conn"]:init() + local console = THREAD.getConsole() + conn(function(a,b,c) + console.print(THREAD:getName().." was triggered!",a,b,c) + end) + multi:newAlarm(2):OnRing(function() + console.print("Fire 2!!!") + conn:Fire(4,5,6) + THREAD.kill() + end) --- local conn = multi:newSystemThreadedConnection("conn"):init() + multi:mainloop() +end) +local console = THREAD.getConsole() +conn(function(a,b,c) + console.print("Mainloop conn got triggered!",a,b,c) +end) --- multi:newSystemThread("Thread_Test_1",function() --- local multi, thread = require("multi"):init() --- local conn = GLOBAL["conn"]:init() --- local console = THREAD.getConsole() --- conn(function(a,b,c) --- console.print(THREAD:getName().." was triggered!",a,b,c) --- end) --- multi:mainloop() --- end) +alarm = multi:newAlarm(1) +alarm:OnRing(function() + console.print("Fire 1!!!") + conn:Fire(1,2,3) +end) --- multi:newSystemThread("Thread_Test_2",function() --- local multi, thread = require("multi"):init() --- local conn = GLOBAL["conn"]:init() --- local console = THREAD.getConsole() --- conn(function(a,b,c) --- console.print(THREAD:getName().." was triggered!",a,b,c) --- end) --- multi:newAlarm(2):OnRing(function() --- console.print("Fire 2!!!") --- conn:Fire(4,5,6) --- THREAD.kill() --- end) +alarm = multi:newAlarm(3):OnRing(function() + multi:newSystemThread("Thread_Test_3",function() + local multi, thread = require("multi"):init() + local conn = GLOBAL["conn"]:init() + local console = THREAD.getConsole() + conn(function(a,b,c) + console.print(THREAD:getName().." was triggered!",a,b,c) + end) + multi:newAlarm(4):OnRing(function() + console.print("Fire 3!!!") + conn:Fire(7,8,9) + end) + multi:mainloop() + end) +end) --- multi:mainloop() --- end) --- local console = THREAD.getConsole() --- conn(function(a,b,c) --- console.print("Mainloop conn got triggered!",a,b,c) --- end) - --- alarm = multi:newAlarm(1) --- alarm:OnRing(function() --- console.print("Fire 1!!!") --- conn:Fire(1,2,3) --- end) - --- alarm = multi:newAlarm(3):OnRing(function() --- multi:newSystemThread("Thread_Test_3",function() --- local multi, thread = require("multi"):init() --- local conn = GLOBAL["conn"]:init() --- local console = THREAD.getConsole() --- conn(function(a,b,c) --- console.print(THREAD:getName().." was triggered!",a,b,c) --- end) --- multi:newAlarm(4):OnRing(function() --- console.print("Fire 3!!!") --- conn:Fire(7,8,9) --- end) --- multi:mainloop() --- end) --- end) - --- multi:newSystemThread("Thread_Test_4",function() --- local multi, thread = require("multi"):init() --- local conn = GLOBAL["conn"]:init() --- local conn2 = multi:newConnection() --- local console = THREAD.getConsole() --- multi:newAlarm(2):OnRing(function() --- conn2:Fire() --- end) --- multi:newThread(function() --- console.print("Conn Test!") --- thread.hold(conn + conn2) --- console.print("It held!") --- end) --- multi:mainloop() --- end) +multi:newSystemThread("Thread_Test_4",function() + local multi, thread = require("multi"):init() + local conn = GLOBAL["conn"]:init() + local conn2 = multi:newConnection() + local console = THREAD.getConsole() + multi:newAlarm(2):OnRing(function() + conn2:Fire() + end) + multi:newThread(function() + console.print("Conn Test!") + thread.hold(conn + conn2) + console.print("It held!") + end) + multi:mainloop() +end) multi:mainloop() \ No newline at end of file