Need for Speed - Endgame optimization limitations
-
Heyhey screepers! I would like to open a discussion regarding our "Need for Speed". Obviously I'm not talking about fast cars or speed of moving objects in general.
I'm talking about code speed.
Currently, there are 7 people with GCL 28 or higher. Meaning these people have gotten their max CPU allowance, 300 CPU. Congratulations!
When you reach this milestone in your screeps career you suddenly start asking yourself exciting questions:
- Do I still need the GCL I'm pumping into the controller?
- Shall I switch to power processing more often?
- Can I start manipulating market prices?
- Do I start building walls now?
- Can I code more efficient so it does more in less time?
- Must I rewrite this so it fits better with my needs?
- Can I get even more (reserved) rooms before running into CPU problems?
All these things are extremely relevant when you're running close near the limit.
However, there comes a time that you got a feeling you can not optimize further, and you start profiling even more. After a while you will find out that some gamestate-changing calls require a lot more than 0.2 CPU.
You'll also find out your memory is a culprit of your "lost" CPU cycles, deserialization of the Memory object takes CPU away.
To tackle some of the problems I'm currently having with the game itself I'd love to open a dialogue with the developers of the game, and you guys, the player base. I'd love to do this to keep the game more interesting at the 300 CPU limit.
Some information about my scripts:
- Currently I'm running at about ~1100 intents/tick (1100 * 0.2 CPU would mean 220 CPU, leaving 80 CPU for memory loading and logic).
- My Memory is heavily optimized for the speed of JSON.parse(), and is ready to utilize the upcoming change of Memory segments ( http://screeps.com/forum/topic/609/PTR-Changelog-2016-10-02 )
- My current overhead for loading memory is 18.54 CPU per tick (717 KB, 18934 objects in total)
- I get hit with GC about every 1.5 ticks. ranging from 2 (80% of the hits) CPU increase to 25 (10% of the hits) CPU increase at that tick. It's hard to get a grasp on this data.
- I measure this by creeps which are not moving, do no pathfinding, and only did "happy-path" actions, meaning they only did a single .harvest or .upgradeController call
This leaves me with +- 60 CPU for game-action related CPU things. Due to my optimizations this is more than enough.
My current problems are:
- I can't grow further, which makes the game less interesting
- Some API calls are waaaayyyy longer than the 0.2 CPU hit you should get according to http://support.screeps.com/hc/en-us/articles/205193752-Important-change-CPU-cost-of-API-methods
- This is mostly due to client-side checks which I can't optimize
- Memory is expensive
- This will luckily be addressed with the Memory segments feature, and will no longer be an issue after that.
My goals in the game are:
- Run as much intents as possible, close to the theoretical max of 1500 actions/tick ( 300 CPU / 0.2 CONST = 1500 intents )
- Build together on something big, be it shared building projects or a new game mechanic yet to be released
- Defeat hernanduer in the Power standings (Coming for you buddy! You're not making it easy)
The way I think the player gets more CONST CPU actions per tick:
Give us access to the intents.set object! This should be an advanced feature, and should not be enabled by default. Maybe only grant access to this once you specify it in your profile. The difference would be that you will no longer receive OK or ERR_NOT_IN_RANGE for example, you have to do your checks yourself! No more if(creep.harvest(stuff) == ERR_NOT_IN_RANGE) { creep.moveTo(stuff); }.
Pros:
- No client side checks
- Less CPU per API-call overall
Cons:
- Heavy(er) server load because checks will have to be done in the backend
- Can be abused by "try and forget"
You could counter the failed intent stuff by penalizing players who perform a wrong intent by deducting 0.4 CPU from the bucket when processing it, and next tick publishing a list of failed intents so the player can see what he did wrong. If the intent succeeded the normal cost of 0.2 will apply.
Give us raw access to the FIND_* and spatial registers, this way no cloning/editting is needed in existing memory (also keeping GC pressure down this way)
Change the constant costs of some of the operations:
move() and harvest() are one of the most frequently used calls. Changing these costs to something lower (0.1 on roads for example, credits to @ags131) will free up more CPU to expand a little bit more.
Change the way you harvest energy/minerals:
- Allow for remote structures which mine for you, and act like a container. (idea form @NhanHo)
In short: I'd like to expand more but I've seem to hit the ceiling in regards to CPU usage. I can't pump out more efficient ways to do stuff right now.
-
I absolutely love the idea of being able to set intents directly, it doesn't even increase server load, as they're already being checked on the processor side anyways. Even though those don't always match the client-side checks (e.g. today I've found another bug that allows easy exploitation - going to report and open a pull request when I get home).
Edit: Adding onto this, I'd absolutely love to contribute to improving the server code, as discussed in one of the slack channels I even thought about writing a custom implementation. Is there any chance we can get involved more into actual development of the game besides feedback?
-
Dear Dissi,
Gaining direct access to setIntent is something I have been hoping for as well. It doesn't seem like it would be too difficult to accomplish. All necessary verifications should already be performed on the processor side anyways. Access to the spatial registers would also be very welcome, but I'm not sure how easy that would be to implement.
However, I strongly disagree with differentiating the base CPU cost of any core action such as move or harvest. The standard 0.2 CPU cost for any set intent is a good standard and I think it should remain that way. The trick would then be to restructure your creeps/processes so that they need to perform fewer actions. For example:
- make 50 part harvesters which only need to harvest 1/10th the time an optimized harvester
- make 50 part haulers even for nearby containers so that they need to move less oftenI have always envisioned that the "endgame" is a shift in strategy where the focus is less on resource/spawn efficiency and instead heavily focusing on CPU efficiency. I agree that we should not be penalized by client side checks which are intended to assist the user. However requesting that the core game mechanics be changed so that players do not need to make radical adjustments after GCL 28 doesn't feel right.
As far as I can tell, It should be possible to run an efficient AI with 45 rooms without having to make radical strategy adjustments as the ones mentioned earlier. With extreme strategies that number could be pushed to 60-80 although I have not made any math on how profitable such strategies might be.
If anything, move() should cost more since it is one of the most expensive functions to process server-side.
Kind regards,
Atavus
-
atavus:
- make 50 part harvesters which only need to harvest 1/10th the time an optimized harvester
- make 50 part haulers even for nearby containers so that they need to move less oftenI tried this, it's not more CPU friendly. The 50 part harvesters is just waste energy as well. You energy income per CPU won't rise if you try this, feel free to try though!
atavus:
However requesting that the core game mechanics be changed so that players do not need to make radical adjustments after GCL 28 doesn't feel right.I think you misinterpreted what I wanted, I'm opening a dialogue here for more lategame variation in tactics. As you can read I've pretty much exhausted any normal way of optimizing my scripts. Obviously less creeps = less CPU.
I'm looking for way we can improve the late-game, and am challenging the community to come up with ideas.
-
To be fair there already is a difference between some intent setting functions. For instance, running a reaction a lab is closer to 0.35 cpu than it is to 0.20 cpu.
-
Ok, let's switch it around and do some math.
Let's assume an inefficient scenario where each source has:
- harvester 1 carry : 6 work : 3 move => 800 energy
- carrier 32 carry : 16 move => 3200 energyMind you this assumes an average distance to a source of 80 units which is pretty extreme. It assumes all your sources need a carrier.
If you double the size of your harvesters and you spawn 2 carriers instead of 1, then in an ideal scenario you are dropping your CPU cost to half. 1 carrier is always waiting and the harvester only harvests half the time.
This means that you can use the extra CPU to mine another source. So you pay 4000 extra energy to gain the use of one more source which will produce 15000 - 8000 over the lifetime of a creep. Assuming an energy overhead for the necessary infrastructure of 4000, that's still 3k energy profit. More importantly, the scenario here presented is pretty inefficient.
50 part creeps are probably unprofitable, but somewhere in between a standard 10 part harvester and a 50 part harvester is a good balance between CPU and energy profit.
Technically a room which has access to 6 sources in total is already a very profitable room. If you would shift away from SK rooms (the extra minerals are no longer important), I can see reaching 45 rooms as a reasonable expectation.
-
"I'm looking for way we can improve the late-game, and am challenging the community to come up with ideas." ~ Dissi
Let me just be mean here for a second.
So, you are challenging the community to come up with ideas which will exclusively benefit the 7 strongest players in the game?
Shouldn't it be the case that these 7 players collaborate and experiment with different tactics and then share their results with the rest of the community?
Shouldn't it be that the best players help lift the whole community to a new level of gameplay?
-
atavus:
If you double the size of your harvesters and you spawn 2 carriers instead of 1, then in an ideal scenario you are dropping your CPU cost to half. 1 carrier is always waiting and the harvester only harvests half the time.No, you pay 4k energy to have extra idling creeps which might overlap actions while walking, costing more CPU, reaching your limit faster due to burst issues ( can be mitigated ).
It's also not what the discussion is about.
I'm trying to aim the discussion more towards the CPU limitations we currently have due to how the game is programmed. I run ~960 creeps + buildings simultaneously with little overhead, the CPU costs are just too high. This can become 1500 creeps of which 440 are idle on a wimp, it's not the issue I'm trying to discuss here.
-
atavus:
So, you are challenging the community to come up with ideas which will exclusively benefit the 7 strongest players in the game?No, you can benefit from the same changes.
-
Ok, let's try a different angle. Let's focus exclusively on harvesters.
Let's assume:
- 20 RCL8 rooms
- average CPU cost per room with remote mining (SK or otherwise) of 10
- average income per room of 1.5m per 24h
- average creep cost per room of 750k
- total harvesters 165
- average harvester cost 850Let's suppose you double the size of your harvesters:
- extra cost per room ~7k
- extra cost empire wide ~140k
- CPU gain 33 (harvesting only half the time)So I'm spending 140k energy to get an extra 2m+ of energy (more rooms) for the exact same CPU.
I think the math is pretty clear. Even assuming that the benefit is not 0.2 per creep (it really should be). Even assuming a benefit of only 0.06 CPU per creep from the double size. That still gives you one extra room and at least 500k energy profit.
I get the feeling there's definitely room for optimization at GCL >30.
-
atavus:
I think the math is pretty clear. Even assuming that the benefit is not 0.2 per creep (it really should be). Even assuming a benefit of only 0.06 CPU per creep from the double size. That still gives you one extra room and at least 500k energy profit.I'm not saying you're wrong, the problem is that it's not what the discussion is about
-
Sorry, I must have misunderstood. I thought the challenge was how you could push the limits after hitting GCL 30.
What I was trying to suggest was that there is no need to discuss about changing the core game mechanics until we have players which have exceeded GCL 45.
On that note, I would still very much appreciate getting access to setIntent. Pretty please @Artem?
-
From my point of view (and ... YMMV of course) : empowering the player with more efficient tools at the cost of more "danger" seems all good : eg, giving us access to lower level, unsafe APIs for the sake of performance (and at the cost of cpu penalty if you misuse) seems a good idea to me.
However I don't see the point in reducing the fixed cpu cost of any thing , you'll just hit that same wall, just a little bit later right ?
-
and ... from my own experiments, even though my efficiency is miles away from yours dissi, it seems i was able to reduce cpu footprint of energy harvesters by having one harvester run both sources in a room (eg, bigger, moving between the two sources) when the sources are close enough.
-
I would love access to the FIND registers and the intents.set object! Also, as an alternative to reducing move cost, perhaps there could be a reduced cost for creeps doing multiple actions? Something like the first action costs .2, then any subsequent actions only cost .1. I feel like this could alleviate a lot of cpu for creeps that move + some action(s) on the same tick. This is based off my assumption that some portion of that .2 constant is accounting for updates to the creep itself, which could be combined when it's doing multiple actions.
-
I'd love to have more options to write efficient code.
Ideally they should come with trade-offs such as direct access to intents idea (lower cpu cost, more challenging to use right) with a penalty for getting it wrong (higher constant cost if conflicts do arise)
As a new player this opinion may not hold much weight, but I'm going to disagree with the notion that raising GCL once past 28 has currently not enough benefits or that the 7 top players who did achieve this should be catered to specifically. First, being high ranked is a status thing. Second, the increased room limit past it does have (some) benefits. It can be used to own an earlier reserved room without fullly developing it, which means:
- no reservers are needed (smallish cpu saving)
- reduces the dropoff distance for remote sources using a lone termina (smallish cpu saving)
- an extra source-keeper-free minerals (smallish cpu saving, also makes balancing minerals easier)
Instead of investing time in changing or developing things that benefit a few players, I'd be happier with progress on general improvements that benefit everyone equally (or give everyone reason to rewrite their codebase, such as the visual thing)
On how to stay engaged once hitting the ceiling: I don't have any ideas. I suspect this is a problem that can not be solved using game mechanics, every MMO has it in some way. No matter what improvements for the players past 28 are added, at some point they'll hit a new ceiling. Even if the restrictions on GCL and cpu were to be entirely removed it'd get boring after a while (infinite growth at a linear rate)
I hope that the power creeps, other future enhancements and the excellent user community are enough reasons to stay engaged for now
-
Relatively new player chiming in here, but I have 25+ years programming experience.
I've found it to be really funny that ultimately this game boils down to trying to optimize JavaScript code for CPU usage. JavaScript has to be one of the worst languages ever invented when it comes to CPU optimizations. The entire benefit of using JavaScript is its asynchronous nature (which we the players are not really able to take advantage of without costing ourselves more CPU) and its amazing efficiency at performing I/O (which again, is useless to we the players).
TL;DR JavaScript is a horrible language for us to be using, if CPU optimization is the end goal of our code.
I'd love to be able to submit C++ code, pay for the compile costs via my bucket, and then see it run at 2x or 3x more CPU efficient than the JavaScript code will ever be capable of running.
Sure JavaScript is a fun language. It's easy for people to learn. It is not at all CPU efficient, and if the game really boils down to CPU efficiency being the highest priority, then ultimately JavaScript is the wrong language to be using.
WTB C++ compatibility!
-
@Xist qualities of the language here are not really that important, we're all using the same, so the field is level
The winner is the one that finds more efficient ways through his code design decisions
-
@Finndibaen I totally understand and agree that the playing field is level if everyone uses JavaScript.
I only meant to suggest that, since the cost of running the servers is almost purely based on how much CPU/RAM is used, and thus the game devs wish for us to make the most CPU efficient code possible, then allowing us to use a language which is significantly more CPU efficient than JavaScript would likely go a long way to reduce their expenses.
I'm sure this is no small amount of work for them as they are very heavily invested in JavaScript. However it's something for them to consider if indeed they do want to save probably-significant money without the consequences of simplifying/reducing the game that we all enjoy playing.