Moon Logic deprecated

by mk-fg

Adds Lua-programmable circuit network combinator. Based on Sandboxed LuaCombinator and LuaCombinator2 mods. Probably won't work in multiplayer games.

Content
2 years ago
1.0 - 1.1
4.97K
Circuit network

g [lua-qiz] UPS Optimization

2 years ago

I have a bunch of moon logic combinators copied around as train station monitors (using ota_update_from_uid). This is all working great, but I am seeing some UPS lags as a result. I minimized the impact by only running once a second, but I was curious on how to optimize things in general.

Are there are any ways to measure the time it takes for a portion of script to execute? Most options I could find online that would let met count milliseconds don't seem to be available (posix.clock_gettime(clk), socket.gettime(), etc). Are there particularly expensive types of operations to watch out for?

2 years ago

Are there are any ways to measure the time it takes for a portion of script to execute?

No, don't think I know of any.
Also remember googling for such timing options wrt factorio specifically, and iirc all feature request of that kind end up bumping into the issue that this kind of thing is guaranteed to be non-deterministic (measuring local cpu time), and as such is guaranteed to break multiplayer, so impossible under developers' vision for the game.

Factorio probably uses mostly-same open-source lua 5.2 implementation as can be downloaded on the internet, and you can easily copy your code routine there, provide same inputs and run it in a loop like 1M times, measure the total, which I bet would be very representative of its performance in factorio (to within couple %), especially for comparison with other code.
On linux I'd just run it as time lua5.2 test.lua from shell, but you can probably wrap it into ms timers and run with less fancy shell on windows to roughly same effect.

And of course maybe you can check general mod performance profiling screen (F6 or somesuch key - check wiki), and disable other mods if they don't leave much cpu time on ticks for this one.

Are there particularly expensive types of operations to watch out for?

Maybe you can make lots of things run even less code by using "irq" signals rather than static delays, if things happen less often than 1/s.
Generally I'd watch out of any iteration, and especially nested loops, which are subject to blowing up exponentially, but that's probably obvious.

I'd maybe also look into using less combinators and more connected circuit networks, and using stock combinators more.
Never really played with very large bases myself, and for most of my games only like 5-10 of these on the map was enough, with many more regular constant/arithmetic/decider ones (like hundreds, incl. automating most train loading), but I can see how one might want to go entirely for lua combinators instead of ever designing gate logic.
Oh, and I also play on much slower speed than 1x, for a much more chill game, so effectively have 2x-4x more time for game/mod logic on each tick, maybe you can use that trick too for a smoother experience.

It's probably too obvious as well, but I think just running the game on faster CPU core(s) can allow it to do more on each frame.
Mostly played the game on AMD Phenom-2 machine I bought in 2011 myself, so suspect your issue might have an entirely different scale that no modern CPU can fix :)

2 years ago
(updated 2 years ago)

copy your code routine there, provide same inputs and run it in a loop

Actually a person in another thread asked for ability to copy-paste environment from combinator just yesterday, which I've added in 0.0.80, and can maybe be quite useful for this purpose - i.e. dump signals/state there, copy, run in a separate script for benchmarking purposes.

VerniciousKnid, do you know about /measured-command? You would use it as you currently use /c in the console so something like /measured-command <Lua snippet>. It will show you how long your Lua snippet took to execute.

There's also the option of using a profiler (via the Factorio Mod Debug extension for VSCode), though that is quite a bit more involved.

2 years ago
(updated 2 years ago)

Oh, I think I forgot about /measured-command.

Mod can probably add some command like /mlc run <mlc-id> [<number-of-times>] to test how fast code on specific combinator runs with whatever environment it has atm, especially if it doesn't affect itself between each run (e.g. doesn't change code paths based on some counter it modifies, or somesuch thing).
That can then work with /measured-command mlc run 1234 1000 for example, with 1k runs like that averaging-out noise and to avoid rounding errors.

2 years ago

Or guess if it's for lua like /c, using remote.call() instead of registered command would be easier.

2 years ago

Something like /measured-command remote.call('mlc', 'run', 1234, 1000) should work from 0.0.81+, to run the code on uid=1234 combinator 1000 times in that example, and then print precise time it took. Run-count at the end can be omitted and defaults to 1.
Such runs can affect output signals and lua environment on the combinator, so might be best to run something that doesn't read and write those at the same time for most consistent results between runs.
If there are any errors, script should count them and print the number in a console/chat msg at the end, as well as last error string.

2 years ago

Also added this question and info to the FAQ, as I think it was asked here before too.

2 years ago

I did some testing with measured-command, and the results don't really point to any bottlenecks. Regardless of the code in the combinator, the execution seems to take about 0.03 to 0.07 milliseconds. Is this just how long it takes to execute a single combinator under usual operation? (obviously individual computer dependent) I'm thinking that my problem really is just number of combinators - I have a few hundred, and that length times the count of combinators more or less corresponds to the amount of UPS delay I'm seeing.

Is there a cost in spinning up the lua engine that each combinator is incurring? I'm curious if I were to implement my own mod if it would be faster or have the same cost.

2 years ago

To clarify, when I say create my own mod I don't mean create a new generic lua combinator, but one that has my desired logic hardcoded.

2 years ago

Is there a cost in spinning up the lua engine that each combinator is incurring?

Don't think so.
Code is load()'ed once into a local variable and then run exactly like any lua function.

There is a cost of processing signals before and after running the code though, which should add some overhead, that should probably vary depending on used signal count.

Regardless of the code in the combinator, the execution seems to take about 0.03 to 0.07 milliseconds.
Is this just how long it takes to execute a single combinator under usual operation?

Here's what that remote call runs:
https://github.com/mk-fg/games/blob/93c3e30/factorio/Moon_Logic/control.lua#L900-L912

So pretty much just st, err = pcall(mlc_env._func), i.e. mlc_env._func() with a error-handling wrapper.
If numbers from that already sum up to roughly same unacceptable number as you're getting with this mod, don't think there's much point changing wrappers, as that's just the code inside those that takes this much time.

But if it's same code running hundreds of times, maybe you don't need to run it that way to get same results.
E.g. templated-in-hundreds production line can probably be replaced by a single mod recipe that gets inputs in same proportion and outputs same things with zero lua code. Or maybe put down one such line with a thing that converts 100x inputs to 1x, and then 1x outputs to 100x.
As mentioned however, I don't really copy-paste megabases myself, so probably don't understand how and why people do it, and such simple solutions don't apply.

1 year, 10 months ago
(updated 1 year, 10 months ago)

Builded ~300 mlc for test, each with delay = 1000; and several lines of code without loops:

show-time-usage:
mod-Moon_Logic: 1.7

1 year, 10 months ago
(updated 1 year, 10 months ago)

So on my PC one mlc that doing nothing (either not powered) consuming ~0.006 ms.

New response