• We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.

Stellaris Dev Diary #149 - Technical improvements

Hi everyone, this is Moah. I’m the tech lead on Stellaris and today I’m here to talk about the free 2.3 "Wolfe" update that will be arriving together with Ancient Relics, and what it brings to the table in terms of tech.

Stellaris is going 64 bits.
People have been clamoring for this for a while now, and various factors have led us to finally do this for this patch. I should temper your expectations though: while many have claimed that this would be a miracle cure for all their issues with Stellaris, the reality is somewhat more tame.

What does it mean?
The one solid benefit is that Stellaris is no longer limited to 4gb of memory, and won’t crash anymore in situations where it was reaching that limit. For people who play on huge galaxies, with many empires, many mods or well into 3000s, this will be a boon.

In terms of performance, though, it doesn’t change much. Without drowning you in technical details, let’s just say that some things go faster because you handle more data at once, some things go slower because you have more data to handle. In the end, our measurements have shown no perceptible difference.

Finally, the last effect of switching to 64 bits is that the game will no longer playable on 32 bits computers or OSes. We don’t think this will affect many people, but there you have it.


What about Performance?
I know that’s everyone’s favourite question, so let’s do our best to talk about it. First, let me dispel some notions floating around in various forums: Stellaris does use multithreading, and we’re always on the lookout for new things to thread. In fact between 2.2.0 and 2.2.7, a huge effort was made to thread jobs and pops, and it’s one of the main drivers of performance improvement between these version.

Pops and jobs are indeed what’s consuming most of our CPU time nowadays. We’ve improved on that by reducing the amount of jobs each pop evaluate. We’ve also found other areas where we were doing too much work, and cut on:
  • Ships calculating their daily regeneration when they’re at full health
  • Off-screen icons being updated
  • Uninhabitable planets doing the same evaluations as populated planets
Why do these seemingly pointless things happen? Well, we generally focus on getting gameplay up and working quickly so that our content designers can iterate quickly, and sometimes things fall through the cracks. Some of these systems are also quite complex and the scale of the new code is not so easily apparent. Sometimes, not limiting the number of targets is good enough because you’re not doing much but then, months later, someone adds more calculations or the number of objects explodes for unrelated reasons, and suddenly you’ve got a performance issue.

Modifiers
One thing that sets Stellaris apart from other PDS title is how much we use (or abuse) modifiers. Everything is a modifier. Modifiers are modified by other modifiers themselves modified by other modifiers, and sometimes by themselves. It’s quite hard to follow, and leads to every value being able to change at any time without your noticing.

“Why don’t you just compute jobs when a new one appears?” has often been asked around these parts. Well, a short answer to that is it’s really hard to know when a new job appears. You can get jobs from any modifier to: country, planet, pops. Each of these can get modifiers from ethics, traditions, perks, events, buildings, jobs, country, planets, pop, technology, etc.

Until now we were trying to calculate modifiers manually, forced to follow the chain in its entirety: when you recompute a country modifier, you then calculate their planets modifiers, and then each planet would recalculate their pops modifiers. Some of our freezes were just that tangled ball of yarn trying to sort itself out.

NexRiPkna2utTqAzF9H0DEjOCwHVsI4EejYO-vMQMh6QwUB-_uP7dXmpjkwXzOOKoiwDqkSzd9tlLmN3DlFN2R06A62od6XxWm8xh99XRDfRFRP3vVj42GBIaDaXSK7jjyKdS39b

This is our modifier flow charts. It’s not quite up to date, but gives you an idea of the complexity of the system (Unpolished because it’s a dev tool, and not made for the article).

No More!
For 2.3 “Wolfe” we have switched to a system of modifier nodes, where each node register what node they follow, and is recalculated when used, following the chain itself. We have modifiers that are more up to date, and calculated only when needed. This also reduces the number of pointless recalculations.

This system has shown remarkable promise, and cut the number of “big freezes” happening around the game (notably after loading, for example). It has some issues, but as we continue working with it, it’ll get better and help both with performance and our programmers’ sanity.

So, what’s the verdict?
In our tests, 2.3 “Wolfe” is between 10% and 30% faster than 2.2.7 right now. Hopefully it’ll stay that way until release, but the nature of the beast is that some of these optimizations break things and fixing the issues negate them, so we can’t promise anything.

IuIGuQ4cXPvjCEMWG_AowiNIFXhzpsPIcphmCVJD79vQqVMqUeZCqCoVfDlWDNZ3YNkAScYAJh2ebft947YsqoOhG7A_4pNBWxjZ6L9se5lkEEImNYZ4uOpTMWj-amEiwSYdirpd


Measurements provided by @sabrenity , using detailed info from the beta build. It’s worth noting the “SHIPS_SERIAL” purple line has since been eliminated.

AI
Another forum favorite, we have done some improvements to the AI. First, with @Glavius ’s permission, we’ve used his job weights to improve general AI job distribution. We’ve also done the usual pass of polish and improvements, and of course taught the AI how to use all our new features.


What else is new?
We’re also getting a new crash reporter that will send your crash report as soon as they happen rather than next time you start the game. We’ve improved our non-steam network stack for connectivity issues, etc.


All right, enough of my yammering. This has turned into a GRRM length novel, and even though there are many more areas we could cover, we’ll just turn this for your perusal.
 
Last edited:
  • 1
Reactions:
For 2.3 “Wolfe” we have switched to a system of modifier nodes, where each node register what node they follow, and is recalculated when used, following the chain itself. We have modifiers that are more up to date, and calculated only when needed. This also reduces the number of pointless recalculations.

This system has shown remarkable promise, and cut the number of “big freezes” happening around the game (notably after loading, for example). It has some issues, but as we continue working with it, it’ll get better and help both with performance and our programmers’ sanity.
Can this be explained further? I am assuming what is meant is that each individual modifier has its own chain, rather than doing the updates to the entire class of modifiers itself (like fully updating all planet modifiers when a single pop is added, ect).
 
I've been wanting a space flu kind of crisis, forcing nations to cooperate to solve an intergalactic extinction level event without fighting for a while. It's unfortunately not in the plans right now.
Jovian Pox crisis hype!
 
I think the issue is that, with the ability to build Gateways, the system has to handle arbitrary amounts of recalculations. Adding a Gateway can, theoretically, change the shortest distance calculation (presumably the heart of the pathfinding system) of every system pair.

Now, for Wormholes, since you cannot artificially create them (I think?), something you could do is the following:

1) At game start, cache every graph of every possible combination of active Wormholes, and create a reference to it.
2) Each Player holds a reference to one of these graphs.
3) When pathfinding is called, just send the reference that Player currently has.
4) When a Wormhole is explored, change the reference the Player holds.

This would increase the game creation time, but should shorten in-play delay by greatly reducing the recalculations needed for wormhole exploration. (It also could be applied to precursor home systems, I think, if those are generated at game creation and not dynamically.)

As for Gateways, that's a more daunting issue. The memory footprint necessary to do my above suggestion for arbitrary numbers of Gateways is likely (literally) astronomical. Even searching the cache for the new reference would likely cause a similar delay to normal.

The two main methods for improving performance here is getting a faster algorithm--which may be possible, but presumably something they are already doing--or improving the cacheing. Likely also being done.

I'm willing to offer my help, as I've had to do quite a bit of pathfinding algorithm work on my current simulation modeling projects.
What if the calculations would be done step by step ( when processor have some spare power ) on daily basis for the entire time of Gateway build?
Increate calculation priority the closer to construction date.
This way it would be calculated when it would be created. In this case what you need to set is GATEWAY_state = aCTIvE and it is ready to go.
 
I've been wanting a space flu kind of crisis, forcing nations to cooperate to solve an intergalactic extinction level event without fighting for a while. It's unfortunately not in the plans right now.
How about Space Thanos? In Space!
 
Aren't those kind of events negligible, it's the daily tick that grinds after a while. If it took a minute to generate a new system 7 times across an entire playthrough, I'd be content if generally things were smoother

We don't know how much the daily tick is affected by the refactoring of the pathfinding graph. If you have, say, 15 Empires in a game, and half of them can build Gateways, what is the number of days it takes for a new Gateway to either be constructed or be activated for any Empire, which necessitates a graph refactoring? My point is that if this is happening about once every 20 days, you will see a stutter on that mark.

Something that might help would be to not update the graph immediately, but only flag that the graph should be changed. Then don't update the graph until someone calls the pathfinding algorithm. Algorithm checks whether the flag for a changed graph is set, and if it is, updates the graph before running the algorithm. This would help if the graph is changing more often than the pathfinding algorithm is called. I just don't know how likely that is under arbitrary conditions.

Limiting the number of Gateways you can build will help spam, but I don't know how much this affects the problem overall.
 
I've been wanting a space flu kind of crisis, forcing nations to cooperate to solve an intergalactic extinction level event without fighting for a while. It's unfortunately not in the plans right now.

Please please please put non-military crises on the cards for future :D it probably makes sense if we get a diplomacy overhaul at some point. Currently the mid and end game crises are only solvable by fighting. Having crises like plagues, galactic stock crash, hyper storms that rearrange lanes etc with diplomatic, economic and scientific solutions would be great.
 
We don't know how much the daily tick is affected by the refactoring of the pathfinding graph. If you have, say, 15 Empires in a game, and half of them can build Gateways, what is the number of days it takes for a new Gateway to either be constructed or be activated for any Empire, which necessitates a graph refactoring? My point is that if this is happening about once every 20 days, you will see a stutter on that mark.

Something that might help would be to not update the graph immediately, but only flag that the graph should be changed. Then don't update the graph until someone calls the pathfinding algorithm. Algorithm checks whether the flag for a changed graph is set, and if it is, updates the graph before running the algorithm. This would help if the graph is changing more often than the pathfinding algorithm is called. I just don't know how likely that is under arbitrary conditions.

Limiting the number of Gateways you can build will help spam, but I don't know how much this affects the problem overall.
My thoughts exactly! just the same i wrote earlier but you explained it much more clearly
 
Best news I heard in ages! Really looking forward to this.
 
Would it be possible to be able to turn off xenocompatability on the startup menu? Not only do I hate how it clogs up the species list with hundreds of new species but most importantly I’ve heard this is also a big cause of lag
 
Making pops easier to kill in war, making them die when food is low, crime is high, or any number of other scenarios would be both realistic and CPU friendly. Make Colonization Hard Again!

Also, make gateway upkeep hard. Having a single gateway doesn't cost much, because you're only paying for "your onramp" to the galactic superhighway. But if you're trying to build your OWN superhighway, well, that will scale up in costs immensely. And if you run out of energy, or alloys, or whatever costs you need for them, they risk exploding. BOOM, GONE, MUAHAHAHAHA.
 
How about Space Thanos? In Space!

Would actually be nice to have something like a relic-related mid- or endgame crisis with the new dlc, where several relics are found throughout the galaxy and a madman tries to collect them all to unleash something terrible..
 
I really like you that 64x is going to be a thing. Do you aggregate job calculations (or parts of calculations) on a planet wide/empire-wide basis?

Like for example, if you have 100 pops working alloy jobs, each will have their own ethics and , because of faction support, different happiness.

I doubt most players would mind if figures were rounded to the nearest 1% or 5% in many cases - like if jobs were initially calculated on an empire level (I.e group up all alloy pops with 60-64% happiness, 65-70% etc),

You could then apply a weighted modifier -built as a 'net weight' the from a table of all your various empire/planetary modifiers, [which could update throughout the month, whilst the main calculations happen at End of month].

So essentially splitt all calculations in to two big halves, by grouping segments of pops (based on and rounded happiness&job) whilst also grouping all relevant modifiers for each job into 1 figure. Then multiply the pop segment by the relevant Net modifier weight.

I have no idea how this would affect whatever calculation system the game is currently coded with.

Also, what's your thoughts on applying the job system to megastructures - needing pops to build a 'megastructure resource' that can be applied to any ongoing construction - instead of alloys or EC.
 
What if the calculations would be done step by step ( when processor have some spare power ) on daily basis for the entire time of Gateway build?
Increate calculation priority the closer to construction date.
This way it would be calculated when it would be created. In this case what you need to set is GATEWAY_state = aCTIvE and it is ready to go

I imagine that the problem with that is that any change for any other gateway (change of diplomacy / access or creation) would throw the calculation away.
Probably the calculation can be made lighter with a good use of ressourses during the calculation though. It seem that the cache is thrown away when technically you can at least keep the calculations valid for all distances that are shorter than the distance to any of the two points to the gateway (those are already calculated so you just have to compare).
 
What if the calculations would be done step by step ( when processor have some spare power ) on daily basis for the entire time of Gateway build?
Increate calculation priority the closer to construction date.
This way it would be calculated when it would be created. In this case what you need to set is GATEWAY_state = aCTIvE and it is ready to go.

If the graph construction is something that can be done 'in steps', and the calculations spread out over that, that would work for gateway construction, sure. I'm not sure if the first point is truly correct...

My thoughts exactly! just the same i wrote earlier but you explained it much more clearly

Not quite, but yes, we're certainly thinking in similar areas. Pathfinding on a graph is such a generally-useful problem to know how to solve, I'm surprised that there aren't more suggestions for the devs.
 
I've been wanting a space flu kind of crisis, forcing nations to cooperate to solve an intergalactic extinction level event without fighting for a while. It's unfortunately not in the plans right now.

I've said several times that this game could really use some kind of massive non-combat crisis. That would be amazing. Or maybe something like a black hole(s) threatening to devour the galaxy.

Stellaris: Reaper's Due

Love the subtitle!
 
I think the issue is that, with the ability to build Gateways, the system has to handle arbitrary amounts of recalculations. Adding a Gateway can, theoretically, change the shortest distance calculation (presumably the heart of the pathfinding system) of every system pair.
This right there is not correct. Opening a Gateway only effects the shortest distance calculation for systems in it's vicinity. Let me elaborate:
Let's for a moment only use Hyperlanes (and Wormholes which in this regard act like very long Hyperlanes)
Assume we have a table that gives us for each two systems A and B The distance from A to B (and of course the Hyperlane used on the shortest path). Needless to say, this table is symmetric, so it also gives us that for the route from B to A.

Now a Gateway opens. We create a second table, that for every System A gives the distance from A to the Gateway (and the Hyperlane). So far not a lot of calculations necessary.
Whenever a new Gateway opens we start doing a BFS from the System it tis in. For each visted system there are two options:
  1. The new Gateway is closer to the visted system then it's shortest distance to a previous Gateway. Then we update it's entry int he shortest-distance-to-gateway table. Then we add all it's neighbours to the BFS-list.
  2. The visted system has already an equally long route to a previous Gateway. Then we don't add it's neighbours to the BFS-List.
After this we have an updated table that gives us shortest distances to gateways. Now for every two Systems A and B the shortest distance between them including both Hyperlanes and Gateways is Min(HyperlaneDistance(A,B), GatewayDistance(A) + GatewayDistance(B))
In both cases the tables deliver the next system on the route as well.

Now we do the same with L-Gates. This opens up one problem: It's possible that the sortes route uses both a Gateway and an L-Gate. But in this case we know that we will use the shortest route between a Gateway and an L-Gate and this can be included in the above calculations without much trouble.

Distance(A,B) = Min(HyperlaneDistance(A,B), GatewayDistance(A) + GatewayDistance(B), LGateDistance(A) + LGateDistance(B), LGateAndGateWayDistance(A,B))
With LGateAndGateWayDistance(A,B) = Min(GateWayDistance(A), LGateDistance(A)) + Min(GateWayDistance(B), LGateDistance(B)) + DistanceBetweenLGateAndGateway.
 
Uninhabitable planets doing the same evaluations as populated planets
Will this change anything for mods that allow for colonizing normally uninhabitable planets?