Need some help improving my CPU usage



  • If you're really tight for CPU you can take this even further, creating oversized creeps with more parts than they need allows them to finish their work with fewer actions and save CPU.

    This is how I managed to run 9 rooms with 10 CPU - I created harvesters with 9 WORK instead of 6 so they would make fewer calls to creep.harvest and cost less CPU. The energy wasted by having the extra parts was far outweighed by the ability to mine more sources. At one point I had them with 12 WORK, which is still a net benefit if you're right up to the CPU cap, but feels a bit excessive.

    👍


  • @systemparadox Thanks for the tip!! At this moment my cpu is near the limit, but i haven't modiffied the creep's number/size. In a future that's the next thing i'll do. Thank you so much!!



  • @calfa said in Need some help improving my CPU usage:

    if(creep.memory.inPosition == true){
        creep.harvest(Game.getObjectById(creep.memory.mySource));
    }else{
        let myContainer = Game.getObjectById(creep.memory.myContainer);
        if(creep.pos.isEqualTo(myContainer.pos)){
            //When miners are created, in their memory mySource equals 0.
            if(creep.memory.mySource == 0){
                creep.memory.mySource = creep.pos.findClosestByPath(FIND_SOURCES).id;
            }else{
                creep.memory.inPosition = true;
        }else{
            //Using Bonzai Ferroni Traveler. Otherwise would just use moveTo() instead.
            creep.travelTo(myContainer);
        }
    }
    

    You might want to consider something about this code: if a miner uses findClosestByPath after spawning, they'll all use the same source until you get a second spawn. Additionally, findClosestByPath is pretty expensive. You're not using it often so it's not that big of a deal, but perhaps still consider changing this method of choosing a source.

    Additionally, you could consider combining myContainer.pos.x and myContainer.pos.y into a single number, so that you no longer have to run isEqualTo but instead can compare two integers.



  • @keenathar 🤔 Yes, i didn't consider that eventually i will have more than 1 spawn per room, and 2 miners spawning at the same tick could be assigned to the same container. Honestly i don't know how to solve that at this moment, but i'm sure i'll figure out how.

    About comparing both integers rather than calling isEqualTo is something i didn't think of since it's something that only happens once per creep, but an improvement is an improvement, so i'll do it too!! (i actually play more for the sake of learning coding than for the game itself, so things like that are even more valuable to me)

    Thanks a bunch!!!



  • My quick solution to multi-spawning issues was to only allow one creep to be spawned each tick. If any of the spawns tries to initiate a spawn it sets room.spawning = true (which only lasts for that tick). The spawning code just returns immediately if that flag is set.

    I've been trying to keep memory usage to a minimum and I seem to use one-tick flags like this a lot.



  • @calfa said in Need some help improving my CPU usage:

    About comparing both integers rather than calling isEqualTo is something i didn't think of since it's something that only happens once per creep

    Generalize it so that you can use it in all your movement code 🙂



  • I would question the value of optimising isEqualTo. It's literally 3 equality checks. If it's not showing up in the profile as a significant portion of the CPU time I wouldn't bother.

    Remember the rule of optimisation: profile first, then optimise only the parts that need it.



  • @systemparadox I do the same, but I went one step further: I just run the spawning code once per room. No flags needed 🙂 I just grab the first spawn off the availableSpawns list, which i build by getting all spawns in the room and filtering off ones that are currently spawning. If no spawns available, just quit the entire function early until next tick.



  • @systemparadox Fuck my life 😂

    I just coded my rooms so that they can only spawn 1 creep each tick to avoid duplicity on their names (name + Game.time), but just found a new issue. On each room's memory i have entries such as "desiredUpgraders = 1".

    Then, on another module, i count creeps that belong to that room like that...

    totalUpgraders = 0;
    for (let i in Game.creeps){
        let thisCreep = Game.creeps[i];
        if(thisCreep.memory.role == 'upgrader'){
            totalUpgraders ++;
        }
        //And so on...
    }
    //And then...
    if(totalUpgraders < desiredUpgraders){
        SpawnCreep('upgrader');
    }
    

    That was working perfectly so far, because there was only one spawn per room, but now that i have a room with controller level 7 and i have 2 spawns it will begin spawning that desired upgrader. Then, room.memory.isSpawning will be set to true for one tick to avoid duplicity on names, but the very next tick it will start spawning another upgrader on the other available spawn because the one being created doesn't exist yet so totalUpgraders < desiredUpgraders still returns true.

    I've been thinking on how to face this situation for a while, but can't see how at this moment. How do u solve this?



  • Creeps exist while they are being spawned. That is, if you Spawn.spawnCreep([MOVE], 'scout1'), on the next tick Game.creeps.scout1 will exist, but with creep.spawning = true.



  • @systemparadox Oh! Then...their memory also exists? Rather than checking my creeps room by room, i could access them all and check instead their thisCreep.memory.myRoom ?

    Thank you so much!! 😄



  • @calfa said in Need some help improving my CPU usage:

    @systemparadox Oh! Then...their memory also exists? Rather than checking my creeps room by room, i could access them all and check instead their thisCreep.memory.myRoom

    I didn't really understand your answer, and i realize now. I just had to replace...

    if(thisCreep.ticksToLive > ticksToDie){}
    

    with

    if(thisCreep.spawning || thisCreep.ticksToLive > ticksToDie){}
    

    Thanks! 😄



  • I keep improving my code trying to reduce CPU consumption, and this is where i am at this moment...(4 rooms CL7 and 5 rooms remote mining)

    [23:28:50] [shard3]
    calls		time		avg		function
    13100		3282.8		0.251		Creep.travelTo
    11058		2307.0		0.209		Creep.move
    8347		1693.2		0.203		Creep.harvest
    5820		1292.5		0.222		Creep.upgradeController
    105958		1195.1		0.011		Room.toJSON
    240191		640.4		0.003		RoomPosition.getRangeTo
    2025		435.6		0.215		Creep.reserveController
    12808		376.6		0.029		RoomPosition.findInRange
    47712		338.7		0.007		Room.find
    8240		309.1		0.038		Creep.toJSON
    398		292.8		0.736		RoomPosition.findClosestByPath
    12002		168.3		0.014		RoomPosition.findClosestByRange
    655		165.0		0.252		Creep.transfer
    696		151.1		0.217		Creep.repair
    441		103.4		0.234		Creep.withdraw
    34968		49.1		0.001		RoomPosition.inRangeTo
    24086		43.0		0.002		RoomPosition.isNearTo
    139		31.7		0.228		Creep.pickup
    14384		30.4		0.002		RoomPosition.getDirectionTo
    13578		25.1		0.002		Game.getObjectById
    33		17.2		0.520		Spawn.createCreep
    4958		8.9		0.002		Structure.toString
    4106		5.5		0.001		RoomPosition.isEqualTo
    Avg: 21.51	Total: 21471.22	Ticks: 998
    

    I tried to find information about stuff like Room.toJSON or Creep.toJSON but haven't found anything helpful. Can you please explain to me what is this?

    Thanks in advance!



  • @calfa said in Need some help improving my CPU usage:

    toJSON

    I think you are save room and creep object to the memory, but I don't understand why so many count of call for this methods. Are you use JSON.stringify some where?


  • Dev Team

    @flyasd1 said in Need some help improving my CPU usage:

    I don't understand why so many count of call for this methods.

    Because game objects are linked to each other?

    Anyway, the best practices for Screeps is to avoid saving game objects to memory at all costs.



  • Game.getObjectById exists for a reason



  • @Flyasd1 @o4kapuk @ObamaLlama Yes...i save some objects in the memory. This is how i started doing it until i had an error, and then started saving their ids only (but older code remained the same because it works).

    I'll rewrite as many code as i can to save only ids or any other important info. Thank you guys 😕

    P.S. I don't use JSON.stringify anywhere