* Fixed spelling, started ideaing for 16.0.0 * Updated files * Updated readme * Updated version * Concat conns now properly transfer events * Testing types * Connections can be % with functions * Updated connections * Fixed issue with double thread activations (Looking for another solution) * Working on issue with love threaded functions not waiting when in a thread * Working on issue where threads created in threads don't work * Fixed broken threads for love * Fixed some issues with threads * removed test * Updated changes.md * Plan on testing parity between the threading modules * Writing tests for system threading * Added test cases for threading, fixed issues. Todo test love2d * Fixed love2d to succeed with tests * All tests working * Updated files for testing * Modified tests to make it more seamless * removed extra __cores in lanes/pseudo * Working on new priority scheme * Working on priority management * Working on custom prioritySchemes * Fixed issues with missing code * Threaded processors * THREAD.exposeENV(), thread:newProcessor() * Typo in changes.md * Fixed typo in pseudoManager * fixing * Trying to fix exposeENV with pseudoThreading * Changes to threads * updated changes.md * Working on systemthreadedprocess, and experimental newProxy for threading * newProxy and STP work * newProxy implemented * Proxies work with connections now :D * Added tstep to STP, updated changes.md * thread.hold(proxy.conn) * Clean up connection events when holding, working on scheduling tasks/threads to system threaded processors * Getting loads of processors implemented * Finished getLoad(type) * Fixed some bugs * Added an easy way to share a table, found some limitations with lanes threading. * THREAD_NAME set for main thread, connections break the rules for proxies * Testing * Really close to portable proxies, currently extreamly unstable! * Debugging what is going on... * Fixed critical issue with coroutine based threads * Removed extra bloat, proxies are portable now! * Started work on the debugManager * Testing actions, fixing bugs with lanes * Testing... * fixing actions * typo fixed * Throw an error when things break * fixing stuff * Fixed issue with errors not going through * Removed system threaded connections, soon to be replaced by proxies * Testing love2d tests * Test love2d * Use later love-build * Use ubuntu for build * Fixed path * Use appimage * use sudo * No window for love2d * Fixed love2d tests * Testing love2d * Use workspace * Moved other tests while testing * actually pull the repo * packagepath set * Fixed pull * Update multi * Removed link * Edited symlink * Added timeout to build * Rewriting loveManager, too much outdated code * Still implementing new love2d threading code * Rewriting love2d threading binding * Working on adding a Hold method to all objects. Will document how they all work when done. * jobqueues having isues with stp * new pack/unpack for tables, current issue is things being turned into strings * Fixed packing of values into threads, need to fix system proxies and system threaded processors * testing... * Not hard crashing when error is encountered * Should now push non 0 exit codes * Push error when an error happens * Closer to getting things working... * Working on new type system, planning out debugmanager * Fixed error code issue * Test for 5.1 * Planning out debugManager * Some work on the debug manager, proxies working on lanes, todo get pseudo manager and love2d working * Working on getting pseudoThreading tests to work * Added function / connection * Added boost method * Document new features to conns, todo fix newTask * Fixed newTask() * Updated changes.md and fixed some bugs * Added thread.defer(func) * Fixed tests on lanes and pseudo threading, todo fix love2d threading * Fixed paths * Working on paths * Testing paths * Add test for rockspec * Fixed issues * Fixed typo * Added test for defer * Threading working in love2d * Fixed, conf * lanes uses a threaded function like waitfor function * Cleaned up changes.md * added priorityManager to rockspec
213 lines
6.0 KiB
Lua
213 lines
6.0 KiB
Lua
-- Advanced process management. Mutates the multi namespace
|
|
local multi, thread = require("multi"):init()
|
|
local ok, chronos = pcall(require, "chronos") -- hpc
|
|
|
|
if not ok then chronos = nil end
|
|
|
|
-- This is an integration, we cannot directly access locals that are in the main file.
|
|
|
|
local PList = {
|
|
multi.Priority_Core,
|
|
multi.Priority_Very_High,
|
|
multi.Priority_High,
|
|
multi.Priority_Above_Normal,
|
|
multi.Priority_Normal,
|
|
multi.Priority_Below_Normal,
|
|
multi.Priority_Low,
|
|
multi.Priority_Very_Low,
|
|
multi.Priority_Idle
|
|
}
|
|
|
|
-- Restructered these functions since they rely on local variables from the core library
|
|
|
|
local mainloop = multi.mainloopRef
|
|
local mainloop_p = multi.mainloop_p
|
|
local uManagerRef = multi.uManagerRef
|
|
local uManagerRefP = multi.uManagerRefP1
|
|
|
|
local PROFILE_COUNT = 5
|
|
|
|
-- self:setCurrentProcess() a bit slower than using the local var, but there isn't another option
|
|
|
|
local priorityManager = multi:newProcessor("Priority Manager", true)
|
|
priorityManager.newThread = function() multi.warn("You cannot spawn threads on the priority manager!") end
|
|
|
|
priorityManager.setPriorityScheme = function() multi.warn("You cannot set priority on the priorityManager!") end
|
|
|
|
local function average(t)
|
|
local sum = 0
|
|
for _,v in pairs(t) do
|
|
sum = sum + v
|
|
end
|
|
return sum / #t
|
|
end
|
|
|
|
local function getPriority(obj)
|
|
local avg = average(obj.__profiling)
|
|
if avg < 0.0002 then
|
|
return PList[1]
|
|
elseif avg < 0.0004 then
|
|
return PList[2]
|
|
elseif avg < 0.0008 then
|
|
return PList[3]
|
|
elseif avg < 0.001 then
|
|
return PList[4]
|
|
elseif avg < 0.0025 then
|
|
return PList[5]
|
|
elseif avg < 0.005 then
|
|
return PList[6]
|
|
elseif avg < 0.008 then
|
|
return PList[7]
|
|
elseif avg < 0.01 then
|
|
return PList[8]
|
|
else
|
|
return PList[9]
|
|
end
|
|
end
|
|
|
|
local start, stop
|
|
|
|
priorityManager.uManager = function(self)
|
|
-- proc.run already checks if the processor is active
|
|
self:setCurrentProcess()
|
|
local Loop=self.Mainloop
|
|
local ctask
|
|
for _D=#Loop,1,-1 do
|
|
ctask = Loop[_D]
|
|
ctask:setCurrentTask()
|
|
start = chronos.nanotime()
|
|
if ctask:Act() then
|
|
stop = chronos.nanotime()
|
|
if ctask.__profiling then
|
|
table.insert(ctask.__profiling, stop - start)
|
|
end
|
|
if ctask.__profiling and #ctask.__profiling == PROFILE_COUNT then
|
|
ctask:setPriority(getPriority(ctask))
|
|
ctask:reallocate(ctask.__restoreProc)
|
|
ctask.__restoreProc = nil
|
|
ctask.__profiling = nil
|
|
end
|
|
end
|
|
self:setCurrentProcess()
|
|
end
|
|
end
|
|
|
|
local function processHook(obj, proc)
|
|
if obj.Type == multi.registerType("process", "processes") or not(obj.IsAnActor) then return end
|
|
obj.__restoreProc = proc
|
|
obj.__profiling = {}
|
|
obj:reallocate(priorityManager)
|
|
end
|
|
|
|
local function init()
|
|
local registry = {}
|
|
|
|
multi.priorityScheme = {
|
|
RoundRobin = "RoundRobin",
|
|
PriorityBased = "PriorityBased",
|
|
TimeBased = "TimeBased"
|
|
}
|
|
|
|
function multi:setProfilerCount(count)
|
|
PROFILE_COUNT = count
|
|
end
|
|
|
|
function multi:recalibrate()
|
|
if self.__processConn then
|
|
local items = self.Mainloop
|
|
for i,v in pairs(items) do
|
|
processHook(v, self)
|
|
end
|
|
else
|
|
multi.error("Cannot recalibrate the priority if not using Time based mangement!")
|
|
end
|
|
end
|
|
|
|
function multi:isRegistredScheme(scheme)
|
|
return registry[name] ~= nil
|
|
end
|
|
|
|
function multi:getRegisteredScheme(scheme)
|
|
return registry[name].mainloop, registry[name].umanager, registry[name].condition
|
|
end
|
|
|
|
local empty_func = function() return true end
|
|
function multi:registerScheme(name,options)
|
|
local mainloop = options.mainloop or multi.error("You must provide a mainloop option when registring a scheme!")
|
|
local umanager = options.umanager or multi.error("You must provide a umanager option when registring a scheme!")
|
|
|
|
if not options.condition then
|
|
multi.warn("You might want to use condition when registring a scheme! A function that returns true has been auto generated for you!")
|
|
end
|
|
|
|
local condition = options.condition or empty_func
|
|
|
|
if registry[name] and not registry[name].static then
|
|
multi.warn("A scheme named: \"" .. name .. "\" has already been registred, overriting!")
|
|
else
|
|
multi.error("A scheme named: \"" .. name .. "\" has already been registred!")
|
|
end
|
|
|
|
registry[name] = {
|
|
mainloop = mainloop,
|
|
umanager = umanger,
|
|
condition = condition,
|
|
static = options.static or false
|
|
}
|
|
|
|
multi.priorityScheme[name] = name
|
|
|
|
return true
|
|
end
|
|
|
|
function multi:setPriorityScheme(scheme)
|
|
|
|
if not self.Type == multi.registerType("process", "processes") or not self.Type == multi.registerType("rootprocess") then
|
|
multi.warn("You should only invoke setPriorityScheme on a processor object!")
|
|
end
|
|
|
|
if scheme == multi.priorityScheme.RoundRobin then
|
|
if self.__processConn then self.OnObjectCreated:Unconnect(self.__processConn) self.__processConn = nil end
|
|
self.mainloop = mainloop
|
|
self.uManager = uManagerRef
|
|
elseif scheme == multi.priorityScheme.PriorityBased then
|
|
if self.__processConn then self.OnObjectCreated:Unconnect(self.__processConn) self.__processConn = nil end
|
|
self.mainloop = mainloop_p
|
|
self.uManager = uManagerRefP
|
|
elseif scheme == multi.priorityScheme.TimeBased then
|
|
if not chronos then return multi.warn("Unable to use TimeBased Priority without the chronos library!") end
|
|
if self.__processConn then multi.warn("Already enabled TimeBased Priority!") end
|
|
self.__processConn = self.OnObjectCreated(processHook)
|
|
self.mainloop = mainloop_p
|
|
self.uManager = uManagerRefP
|
|
elseif self:isRegistredScheme(scheme) then
|
|
local mainloop, umanager, condition = self:getRegisteredScheme(scheme)
|
|
if condition() then
|
|
self.mainloop = mainloop
|
|
self.uManager = umanager
|
|
end
|
|
else
|
|
self.error("Invalid priority scheme selected!")
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
local function init_chronos()
|
|
-- Let's implement a higher precision clock
|
|
multi.setClock(chronos.nanotime) -- This is also in .000 format. So a plug and play works.
|
|
thread:newThread("System Priority Manager", function()
|
|
while true do
|
|
thread.yield()
|
|
priorityManager.run()
|
|
end
|
|
end)
|
|
end
|
|
|
|
if chronos then
|
|
init_chronos()
|
|
else
|
|
multi.warn("In order to have time based priority management, you need to install the chronos library!")
|
|
end
|
|
|
|
init() |