Factober 5400

clux October 30, 2022 [gaming] #linux

Round two of escapism this year. This is a post for myself with various information as a conclusion to my recent fixation into designing an efficient and compact factorio megabase.

Plan

I keep coming back to this game about once a year. There is something very soothing about the type of play this game encourages. Playing factorio basically feels like being part of some parallel software project; there's builtin dashboards, circuit logic, sharable blueprints, benchmarks, optimizations, and all without the usual externalities of a large software org/project. And at this point for me, it's all about the optimization and theorycrafting.

I set out with the following goal:

produce 2 full blue lanes of every science or 5400 SPM (Science Per Minute)

Certain cheats were used to avoid the less challenging parts of the game:

this lets us focus on the parts of the game that's more interesting to me; optimizing the factory without having to deal with stuff running out or setting up new chaotic trains all the time. It also enables us to optimize the medium sized factory pieces in complete isolation without suddenly being limited by ore or UPS (that's the equivalent part of managing a software project I am trying to avoid).

Copy-pasting small cell bases is currently the leading way to get the most productive bases without choking the game (i.e. maintaining 60 UPS).

We set out to make each science build be entirely self-contained with just a single train station as an output, and we built upon an old starter base that had already achieved almost 200 mining productivity.

Sideprojects

But before we get into it, here are several other things we built along the way that (in true factorio style) did not in any way contribute to the main goal.

Wildlife Preserve

..to justify all those military upgrades:

which we eventually eradicated in a comically inelegant way:

Fishing Outpost

A sustainable ecosystem catching 600 fish over its lifetime on its own power/robo network. Built right above the launchers:

Wood Burner

An automated train service to get rid of all that wood:

(normally triggers automatically, but there were no wood in the requester chests).

Factory Designs

Rails

When starting out with production/purple science I originally had 16 full blue belts of rails that fed into the purple science factories. Now we make rails inline in a single factory that feeds 4 purple science assemblers:

I've not seen anyone else do this, but it works pretty well. It sushies sticks around two columns, and does a bit of crate magic to fit 6 input inserters, 3 input lanes, and 4 output inserters inside a 12 beaconed bounding box, but it actually works in the end.

Green Circuit / Plastic Row

One of the more optimized factory pieces. A single lane that produces a mostly full, mixed plastic/green blue belt.

It requires very precise spawning of coal, iron, copper so that we can have 2 chemical plants for plastic, and 4 smelters of iron + copper for a single 12 beaconed green factory. Some of the time all the furnaces are running:

The green factory is what requires special attention here:

One green factory alone can actually ALMOST supply a half belt (22.4 out of 22.5) if you can fully beacon it. It's just that doing this is very difficult because it takes more than a full blue belt of copper cables that it is very hard to supply it while making room for all the the iron and the outputs. This is why there's a car in between the beacons that serves as a chest.

A car can be picked up from and inserted to at very strange angles at more than one length so it's great for fitting irregular gaps that doesn't work with chests (or would require more inserters). The game doesn't want you to do this though. It cannot be copy-pasted so you have to plant it manually. Doshington showcases the pain this type of design leads to .

You actually have to remove one middle beacon when the inserters starts running to trick the inserters to lock onto the car before planting the beacon down again (otherwise they want to grab the speed modules).

The end result is that you can transfer 24 cables to the assembler through a one space gap on every swing cycle.

Red Circuit Row

Continuing onwards from the green / plastic row, is another inline copper smelter section that joins into a nearly full copper cable assembler, that sufficiently feeds 8 factories of red chips. The red chips are also inserter clocked so they all swing together which looks very satisfying, but I don't think it actually helps with UPS.

This joins onto the green setup so we can end up with these huge stacks for large red factories like this one for RCUs:

Low Density Row

A full row of low density structures can consist of 10 fully beaconed factories supplied by two lanes of copper. It needs a lot of belts, and manual input setup, plus a bunch of inserters to load onto the belt and back in from the belt, so we searched for a more direct setup (without sacrificing too much at the number of machines).

The end setup has 20 smelters to 10 LDS assemblers, which is an extra 4 smelters than is needed, so we beacon them slightly less, but end up with 100% direct insertion on copper. The downside? Lots and lots of cars.

This 70/s LDS factory for space science consists of 14 rows of 10 cars each, which is definitely a hassle to setup and filter.

Ideally the equally sized steel would be lined up to face LDS on the input side (like they are in yellow science below), because here we mix belts first then use splitters later just to avoid a 14 lane wide thing through the base.

Regardless, it looks different to everything else and is kind of beautiful at night:

Enjoying the efficiency of the ratios. All the smelters are running (94% avg utilization).

Labs

Extracted this more conventional lab design to test it out UPS Wars 6: Labs for this with this entry. Nothing remarkable, except perhaps for the long winding belts in different direction. It's slightly overscaled to ensure it will fully drain half belts.

Trains

All of the science cities / space component cities unload onto one of two major unload depots.

The main depots have robo networks to distribute nuclear fuel from a single supply train and they only stop at the hub (which is enough).

Lab Depot

Lab depot looks like a close-up of a complicated circuit:

Very happy with this unload station. We pull exactly 4 half-belts and that can be perfectly filled via two inserters (with an 8 size override) at the cost of less buffer chests (that we don't need those). No splitters anywhere!

Rocket Depot

Probably not the most efficient train unloading, but gotta get 4 wagons of stuff into 6 launchers via 2 inserters per launcher so it's tricky.

Lot's of 2x3 splitters and an eventually emptying unloader with a priority line down to satellites... It's ultimately a little overscaled compared to the other sciences so a few seconds of semi-filled belts, while not particularly efficient, doesn't hurt production.

Nuclear Fuel

A minimal fuel factory that supplies all trains (piggy-backing on any oil refinery because it uses basically nothing). It's almost never active because it only has destination stops available when the hubs have less than 200 items on the receiving chests (circuit network on the receiving side).

Science Cities

Quickly going through these with factorio calc links.

Red

Max beaconing reds would give an awkward ratio whereas doing pairs here gives us just enough with 12F each column. It would be possible to do 11F we did some at higher beaconing though.

Green

Max beaconed smelters and an ad-hoc <4 half belt output of green circuits, and only max beaconing the last pack factory to fill the lane. Again, max beaconing is just not enough with 12F per column pair, so doing pairs with one last max beaconed for 14Fx4. Zero splitters. More gear factories than necessary, but more direct insertion.

both red + green on the map:

Military

Annoyingly large for something that's off most of the time. Lots of clocked smelters, and the actual main ingredient factories are tiny.. Did a cool inline wall thing for each row for the actual science pack, and a big grenade factory, but lots of room for improvement.

One fun thing here though; this factory shuts off its own power when the train station buffer chests is full and no trains are at the station (circuit network connected to the chests and the train station via a combinator). This saves on power, but not on UPS, sadly.

Chemical

All ore/oil/reds + inputs for reds on the left through the green car lane setup, and then on the right inline sulfur (turns out one chemical plant can supply 45/s chemical science). Uses basic oil here because it's not the most demanding, but other peoples' comments suggest it's probably a wash performance wise.

Production

a huge chunk of the factory is literally just dealing with steel for rails and furnaces: which is a slightly overscaled (as can be seen from the few inactive furnaces), but it's a bit unevenly drawn from atm.

Utility

Slightly overscaled (60F) and undersupplied (can supply 59F). 57F ended up in an awkward 3 column build that needed to be split a lot. Best to stick to 4 columns if you are going to load onto 4 wagons. Oil is split into two advanced oil parts; inner one for lube/sulfuric and the outer just for petroleum for LDS.

Space Science

Can just be done with six rocket launchers running near constantly provided we have the ingredients.

RCU

Slightly overscaled because the speed module row looked awkward when optimal. Probably one of the most streamlined parts, but also most heavily abuses ore spawning (mixed lane inputs for both speed modules and blue processors). Blue build is from Stevetrov's cell base with a slight beaconing modification. Tried tons of blue builds for this and they're either all massive (like this), or they need double the amount of inserters for slightly more production, or they are smaller, but need so many belt inputs of plates that it's super awkward to plot down and less efficient. Didn't benchmark this for UPS, just went with gut feel based on smelter uptime, inserter numbers and inserter activity.

LDS

Supplies both rockets and satellites.

RF CF + RF2

Partially from coal liquefaction just because i wanted to learn how to do it well. It's probably not the most optimal choice since it needs lots of mixed coal belts to get the coal in that deep (yes, yes).

CF build is undersupplied with 12 refineries, but doing it that way allows us not to copy paste the advanced oil one another time. It ends up being almost perfectly scaled for the rockets + satellites. Belts just start to fill before the next train arrives.

All the solid fuel factories piggy-back on the ore clock for less swings.

Pretty happy about the beaconing line-up with the refineries and chemical plants:

Satellites

The final component. It's better to look at calculator links for Solar + Accumulators + Processors (the real output part of this chunk) because we leech LDS + RF from the trains.

It's a pretty ugly mess that was designed early, but it's clocked and beaconed everywhere. Oh, and there's only 5 inserters per sulfuric acid factory because cars.

Optimization

We tried several major optimization strategies:

and in general downscaling and optimizing flow:

Beyond the linked posts, the following technicalfactorio subreddit posts, and factorio benchmarks were also helpful:

We did not go to the full-out direct insertion lengths that the most efficient bases go to where everything is inlined (because imo it ends up looking chaotic and huge, with lots of factories ending up idle a lot of the time), but it was truly fascinating to see the amount of rabbit holes you can go down here to optimize.

From the limited amount of testing I personally did. These helped:

while these had no noticable improvements:

Initial Measurements

When doing this set of measurements the base looked like this:

After all the optimizations above; we measured the following rough percentages of time of where the time was being spent in the game's update loop:

SourcePercentms
Entity update67%4.45ms
Elecric network13%0.85ms
Heat manager9%0.62ms
Transport lines8%0.57ms
Circuit network2%0.18ms
Trains1%0.06ms

where the entities were broken down further using show-entity-time-usage:

Entity ClassPercentms
Inserter46%1.80ms
Generator15%0.60ms
Boiler11%0.44ms
Furnace8%0.31ms
Assembler7%0.29ms
Miners5%0.19ms
Labs1%0.04ms

which illustrates why inserter-clocking can be so effective - as it's always such a big part of a factory - but it also highlights the next offender; nuclear.

This is actually a over a quarter of the time. Not what I had expected from a not-that-badly-designed nuclear setup (no steam storage, minimal exchanger network, optimal reactor efficiency bonuses). It's a lot more than people publically estimate, but to give them some credit, the percentage seen on my end would be amplified by already having optimized the hell out of all the inserters.

We ran the base on two big nuclear reactors sites producing 33GW in total.

This reactor block gave us ~60% of the power output with 120 of the 204 total reactors.

Opening up the save in creative mode and ripping out nuclear in favour of an infinite energy interface bumped UPS from 150 to over 200.. how would that translate if we used nearly a million solar panels instead? how much space would that take? how much time would that take...

Solar Project

Well, I had already sunk this much time into it, so thought I'd spend a weekend on it. How fun could it be?

Well, the answer is somewhat.. Provided you shut off the rest of the factory (so you can run 4-8x speed), and then run boost around with a bunch of rc'd spidertrons:

with some strategic landfill factories taking advantage of huge mining prod:

Still, definitely a repetivite background task (that took two days..)

..but how did it measure up?

On gamespeed 5 we saw a near 40% improvement to UPS from 150 to 208.

Breaking the new measurements (1, 2) down, we see:

SourcePercentmsChange
Entity update71%3.12ms-1.33ms
Transport lines13%0.57ms0
Elecric network11%0.48ms-0.38ms
Circuit network4%0.17ms0
Trains1%0.06ms0
Heat manager0%0.00ms-0.62ms

and looking into the entities:

Entity ClassPercentmsChange
Inserter72%2.29ms-0.49ms
Furnace11%0.35ms~0
Assembler9%0.29ms~0
Miners6%0.19ms0
Labs1%0.04ms0
Boiler0%0.01ms-0.43ms
Generator0%0.00ms-0.60ms

(There's likely only precision to one decimal place here as we saw saw 0.04ms changes in furnace and assemblers despite having no actual changes in game. The numbers do have some variance on their own in the big base and we are just operating on screenshots.)

The update loop itself saw a nearly equivalent improvement with 6.24ms to 4.53ms.

End Performance

The UPS went from around 110 to 208 on average from redesigns, clocking and the mentioned tweaks, where a good chunk of this came from the base design itself. The most braindead change with the biggest improvement was switching to solar (with nearly 40% improvement at the time - your mileage will vary). The changes with the most performance gains by time investment was turning on large pages (5min job), and turning off + clearing pollution (1min job).

In the end, the island now looks like this:

i.e. largely the same, but without nuclear, and solar everywhere.

how much solar? oh i'm sorry, that screenshot was cropped..

yeah. that's a lot more than expected. When designing solar, ensure you overscale by 42% to cover the night.

Blueprints

Exported these pieces: factorio blueprints

Commands

Expand Commands

One time commands:

Spawn resources:

/c game.player.surface.create_entity({name="crude-oil", amount=10000000, position={game.player.position.x, game.player.position.y}})

Delete resources (of any kind) in a 10x10 square around you:

/c local surface=game.player.surface local size=10 local pos=game.player.position  for _, e in pairs(surface.find_entities_filtered{area={{pos.x-size, pos.y-size},{pos.x+size, pos.y+size}}, type="resource"})      do e.destroy()  end

Spawn a 2x4 water pond below you:

/c
local waterTiles = {}
for y=2,4 do
 for x=-2,2 do
  table.insert(waterTiles, {name="water", position={game.players[1].position.x+x, game.players[1].position.y+y}})
 end
 game.players[1].surface.set_tiles(waterTiles)
end

Disable cars (see the cars as chests benchmark):

 /c for _, ent in pairs(game.player.surface.find_entities_filtered{name = "car"}) do ent.active = false end

Large pages

Install mimalloc and set start command on factorio via steam:

LD_PRELOAD=/usr/lib/libmimalloc.so MIMALLOC_PAGE_RESET=0 MIMALLOC_LARGE_OS_PAGES=1 %command%

Settings are documented via mi-alloc. Large pages makes the most difference, but huge pages also works well.

Results

In the end, all the optimizations meant we could run the 5400 SPM base at 210 UPS on my machine (i.e. the game managed to run the game at 3.5x real speed on average). With 20% productivity modules in labs, and that game speed scale, we effectively research ~23k science per minute, or 1.4 million science per hour.

If you want to view it interactively or play it, you can download or view full base/save on factoriobox.