Idea for threading
Posted: Thu May 04, 2017 8:40 am
I am currently at situation where I need run my factory with speed 0.3 with 3.6Ghz i7 so I start thinking that there has to be way. I cannot solve that with buying faster processor because there is no processor at market what can run that simulation at realtime with single core. Anyway there is processors where is enough cores to run it. With unlimited science that problem come more and more relevant.
I am not familiar with factorio code but I am very familiar with problems and development pain what multi threading brings. Locking all objects is out of options. There has been some kind "clusterio" idea where is point but it smells like glue. So combining these two ideas here is my proposal. Sorry that I dont know what terms you use in house so I fist clarify my terms
- Item: Item what interacts other items (belt, factory, inserter etc)
- tag: Id, pointer or some other one byte identifier given for each item (explained more at later)
- Thread intermediate item. Item what have special properties regarding to threading.
So idea is that example once at 10 minutes or even one in one hour(if it is very slow process) there run optimizer what start walk item interaction tree. It take one item and check what interaction items it have. Example inserter have usual near by belt and factory. It give tag 1 to each item. When that tree walk is reached limits it stops. Then it find next orphan item. It start walking that tree and give tag 2 for them. So it do that so many times that there is no orphan items.
Now we have interaction groups what we can give to separated worker threads. Each thread will keep tick sync with lock. So they can pick interaction groups from pool as fat there is none. Then they need wait until all other threads release their tick lock. That way all groups will be calculated once per tick and after that there is common calculations what are explained That will not cause changes for current simulation code.
So now we have problem that we can put separated factors for one map but you cannot move your products between groups and if 2 group touch threading will blow up....
For blow up problem my suggestion is that if you plant new item it will mark it as new and it is not counted to current tick. After tick it will check that if there is new items it will check witch group it will interact and add tag for that new item. If item touch to 2 different group then it will take larger group tag and add it to smaller group items. So groups will be merged. If that item is removed there groups will keep merged until next optimizer round.
And because we want big factory, not many small ones we need interaction for groups. For that we can use trains. If trains are exception, we can do that each time when train stop it will check what interaction groups it have and migrate that train to that group. If that train approach feels too complicated then one way to do it is make some kind transfer dock item. It can be example 2x16 item or even larger what include internally 2 huge chests. Both chests have own thread tag. When you put items inside of it it will balance internal chests after each tick. So then it can informed for players that do not put thousands of them, it will kill your performance.
For power grid there can be "HVDC station (check wikipedia if you dont know what it is)" what basically contains two accumulator without current limit or with huge current limit at it got balanced after each tick.
So that way game is still one instance with multiple threads. Threading areas are dynamic and most probably impact for code is quite limited (depending how that rendered engine have connected to simulation engine)
And for multiplayer lag I suggest feature what allow set allow server throttle setting up. That will do so that each client will report to server that if they are behind of server at simulation. If there is client connected what is behind then server will slow down that simulation. If not then it will speed up that simulation. Probably min and max speed is also good parameters. That probably helps to lag spikes at client and is quite trivial to implement.
I am not familiar with factorio code but I am very familiar with problems and development pain what multi threading brings. Locking all objects is out of options. There has been some kind "clusterio" idea where is point but it smells like glue. So combining these two ideas here is my proposal. Sorry that I dont know what terms you use in house so I fist clarify my terms
- Item: Item what interacts other items (belt, factory, inserter etc)
- tag: Id, pointer or some other one byte identifier given for each item (explained more at later)
- Thread intermediate item. Item what have special properties regarding to threading.
So idea is that example once at 10 minutes or even one in one hour(if it is very slow process) there run optimizer what start walk item interaction tree. It take one item and check what interaction items it have. Example inserter have usual near by belt and factory. It give tag 1 to each item. When that tree walk is reached limits it stops. Then it find next orphan item. It start walking that tree and give tag 2 for them. So it do that so many times that there is no orphan items.
Now we have interaction groups what we can give to separated worker threads. Each thread will keep tick sync with lock. So they can pick interaction groups from pool as fat there is none. Then they need wait until all other threads release their tick lock. That way all groups will be calculated once per tick and after that there is common calculations what are explained That will not cause changes for current simulation code.
So now we have problem that we can put separated factors for one map but you cannot move your products between groups and if 2 group touch threading will blow up....
For blow up problem my suggestion is that if you plant new item it will mark it as new and it is not counted to current tick. After tick it will check that if there is new items it will check witch group it will interact and add tag for that new item. If item touch to 2 different group then it will take larger group tag and add it to smaller group items. So groups will be merged. If that item is removed there groups will keep merged until next optimizer round.
And because we want big factory, not many small ones we need interaction for groups. For that we can use trains. If trains are exception, we can do that each time when train stop it will check what interaction groups it have and migrate that train to that group. If that train approach feels too complicated then one way to do it is make some kind transfer dock item. It can be example 2x16 item or even larger what include internally 2 huge chests. Both chests have own thread tag. When you put items inside of it it will balance internal chests after each tick. So then it can informed for players that do not put thousands of them, it will kill your performance.
For power grid there can be "HVDC station (check wikipedia if you dont know what it is)" what basically contains two accumulator without current limit or with huge current limit at it got balanced after each tick.
So that way game is still one instance with multiple threads. Threading areas are dynamic and most probably impact for code is quite limited (depending how that rendered engine have connected to simulation engine)
And for multiplayer lag I suggest feature what allow set allow server throttle setting up. That will do so that each client will report to server that if they are behind of server at simulation. If there is client connected what is behind then server will slow down that simulation. If not then it will speed up that simulation. Probably min and max speed is also good parameters. That probably helps to lag spikes at client and is quite trivial to implement.