Remove the CPU cost of having memory and scale available memory akin to CPU



  • As it is for everthing we have in memory we have to pay serialisation cost every tick. The way default serialiser works it also severily punishes using memory to store s=structured information, for example an object storing 50 properties.

    Result of that is people very quickly learn to not use memory and instead use flags, specifically flag names as they can store information for lower degree of cost (how much exactly depends on specific use of flag, boolean flags are almost free, information flags are at cost of one explode call). And they do that not because they are out of memory, but because Memory is so heavy on CPU.

     

    I think that this ia a bit of nonsensical. CPU and Memory are supposed to be our two core building blocks to build our little empires. And while I agree that we should be optimising our memory, we shouldn't do it due to artificial CPU cost attached to having it (not even using it), but because we've ran out of it, and until that happens there really shouldn't be any CPU cost to having stuff in memory. And it for sure shouldn't be cheaper to use flags to do what memory was designed to do (it can be the same cost just fine).

    I simply fail what it brings to the game beside more confusion and need to work around artificially imposed limitation and wirting serializers instead of focusing on programming AI.

    To balance things out, why not lower the amount of memory available and make it scale akin to how cpu scales now?

     

    I belive that implementing that would remove one of newbie traps that exists right now (not using flags instead of memory), it will also turn memory into what it was supposed to be (I think) and all of that without sacrificing any depth of the game, as going with flags still has it's own benefits. Just that instead of cramming as much information as you can into the name, you can safely store them in that flags memory.

     

     

     

     

     


  • Culture

    Please read:

    http://support.screeps.com/hc/en-us/articles/205395772-Important-change-Memory-parsing-

     

    I agree on the scaling part of memory per GCL level, but removing serialization costs all together is kind of a big move. I know a lot of players, including myself, have worked hard to create complex data structures which have fast access times,and are low-cost for JSON.parse() actions.

    You can always use http://support.screeps.com/hc/en-us/articles/205619121-RawMemory to optimize even further. So far I've not needed this optimization step.

    Yo give a bit of background:

    I currently have about 780 KB in use and it takes 17 CPU to load this every tick. 

    It's part of growing your GCL to deal with the increase in Memory, and managing it effectively. If it weren't for this my data structures would have been quite sloppy/spammy.

    I do understand where your frustration comes from, and using flags to store data is quite a viable strategy, I use it on small parts of my code as well.

     

     

     



  • Not as much as frustration, I can put up a complete memory-with-flag replacement system for what I do now in probably 2-4 hours (maybe second that for edge cases) and have it fully transparent, heck even making its own decision whether to flag it or memory it. I didn't bother yet as I am still not close to CPU limit.

    But feasibility isn't the point - question of what good does that bring to the gameplay is. Would that change invalidate your flag system? Nope, it still will be far ahead of someone using just memory, not only in terms of scale but also flexibility. It will howered remove going with flags as only possible option, as going with memory past 5 rooms is bigger issue than sticking with moveTo. Seriously:

    So really I ask what actual benefit to game itself it brings? In the end this is supposed to be more of a strategy game, and that should be it's focus, with optimisation of internals like Memory serialisation becoming only a problem as you start to grow to the really big leagues.


  • Culture

    I challenge you to replace the memory with a flag-only system. It'd be awesome to see.

    The costs of memory are only at deserialization of the memory, the very first call to it.

    The costs of flags is about 0.2 per alter-call. 

     

    It's more of an end-game thing you have to worry about.



  • Is there actually a limit of how many flags you can set? I haven't seen any in the documentation.

    Otherwise I suppose at some point someone will exploit it (or have a bug in the code) and put down millions of flags, and the devs will have to act. This kinda prevent me from using flags, as I expect them to be nerfed at some point.


  • Culture

    I think you have to see over how you use memory. My memory cpu usage is non-existent and I don't use flags to compensate it.



  • I'm in the same boat as Stybbe; I'm running 8 rooms and the test code in the link Dissi posted (updated to use Game.cpu.getUsed() instead of Game.getUsedCPU() ) shows me burning less than an average of 0.7 CPU per tick, with a highest value of 1.9.  Visually watching the data, most ticks are around 0.5.  At < 1% of my total available CPU, that's really not a problem yet.  I would not be surprised if it becomes a problem later... but as Dissi pointed out, that's an end-game optimization concern, and it provides a new challenge there.

    Using flags as binary flags is an interesting solution I'd been considering from an ease-of-modification standpoint and I should move to that so I don't have to make a full commit just to toggle on/off debug output.  I haven't actually implemented any of that yet though; I'm just running off direct memory accesses.



  • Actual usage depends on how you use the memory. I had the robust build from the very start that is flexible and configurable per room with memory in fine grain details, with order of things, turret targetting priorties, how to handle repairs etc, all of those are defined in memory. And that comes from the simple fact that this is what memory, at least from new players perspective, seems to be for - data you want to be persistent and available as you go along. Moving them from all rooms to binary flags and/or single units of memory shared across rooms with option to override + couple other "optimisations" to make it work better with the basic serialiser didn't shave off 1.9 cpu, it shaved 10 of it. 

    And really, for what gain is that there? We already have people using very little memory (I will be very surprised if there is more than 2 hands worth of people how utilise half of it), a resource that in normal programming is extremely valuable and used in exactly as container for arbitrary data and structures that we want to work on to save CPU, not potentially increase it. I simply fail to see any reason for it to exist as it is now, as it only adds some arbitrary complexity and raises the entry ladder by a pitfall. Worth adding that unless you profile especially for it you won't even know that it's ruining your perofmrnace, because who would expect memory to cost you CPU just for having stuff in it?

    Seems like a lot of bad to me for really little (no?) gain. We could still force people to optimise their memory by drasticly reducing it's availability, without the hidden CPU tax and with increased transparency.


  • Culture

    > who would expect memory to cost you CPU just for having stuff in it?

    Well, if you searched for it on the site, you would know, because one of the very first articles turned up tells you about it.

    It's intended behavior. Your memory costs more or less to deserialize based on how you write your code, and whether you like it or not, that cost has to be paid by someone. Either you pay for it, or the server gives it to you for free.

    It clearly used to be free - but that means that the server now takes on additional load and ticks take longer to execute.

     

    By the way, I use memory extensively and it never takes me more than 5 cpu to deserialize. Yeah, you're going to have to learn to optimize your code in ways you didn't think were important to write an AI. That doesn't mean that you shouldn't have to do it just because it doesn't meet your expectations.

    It's very unlikely that a beginner will ever run into this problem, and when they do, they've probably written quite a bit of code. Expecting to have to optimize it later is just par for the course.



  • Given that explanation of it only exists in that changelog and on bottom of single documentation page + the fact that many people do not know about it tends to beg to differ. Granted that it's easy to find it once you know about it, but isn't everything?

     

    But that is beside the point discussed, could you maybe elaborate and explain  what would be the downside of proposed solution? You will still need to optimise your memory, hell, more than you do now most likely, but the limitation and costs of it will be visible and transparent even at a glance, not hidden and require dilligent profiling. 

    It's also worth noting that the code you are shown in tutorial, which I imagine many players use as base to build upon, is actually extrmeely prone to cpu-heavy memory generation. And all that for gameplay benefits that, at least for me, remain a mystery.


  • Culture

    If it's just a documentation issue, sure. The documentation should be better organized.

    It's not about gameplay benefits, at least not directly.

    The way you structure your memory has an impact on its deserialization cost. That is reality. It is physics. You can't just handwave it away and say "well, I should get that for free!" You can store 1MB of data that doesn't cost very much to deserialize, or you can store 20KB that costs a huge amount to deserialize. If you don't pay that cost, then who? The servers have to deserialize your memory. It's either charged to you or it isn't, and if it isn't, well, then the players won't be aware of that cost, and they'll structure their memory in a suboptimal way, and we'll get 20 second ticks because no one understands what the true costs are.

    The tutorial has you using at most... three? memory values. All I can recall is the state variable for the creep that controls whether it's dropping off. That's hardly leading you down a garden path, and a single value per creep is not going to work.

    Look, I'd love to get 200KB of memory and a free deserialize step. But I know that's not going to happen because deserialization has a CPU cost and someone has to pay it. And it should be me that pays it, since I'm the one that decides what goes into it. Putting the responsibility on the players means that we all benefit from faster tick times.


  • Culture

    "a single value per creep is not going to work" should be "a single value per creep is not going to be any sort of problem".



  • So while you agree that it doesn't benefit the game in any way, or at least can't come up with any reason how it does, you say that it should stay as it is anyway becuase in your guess otherwise the game will, I don't know what, financially collapse? Tick will become 18 seconds long? Either of this is a business issue, on which neither of us has competency or necessary knowledge to discuss with any merit (unless you are one of the devs and have access to business numbers), so let's stay at discussing what we can be certain about - gameplay.

    But as much as I would like to, there is just nothing else for me to add in that regardas you didn't raise any gameplay points to tackle. Best I can do is reiterate that this is creating an uneccessary learning curve without apparent benefit which is not good for new players in any way shape or form.


  • Culture

    The gameplay benefit is the same as the reason for limiting CPU. Your code has costs. You should be charged for those costs. You should optimize your code to reduce those costs. There's no reason to optimize for costs you can't see.



  • To reiterate what you said is: "we need to put the artificail cpu cost in that doesn't make sense from gameplay perspective but we do so for [business reasons]" and outside of devs we are not in position to make or suggest that call.

    And if were to read the suggestion entirely, and the replies, no one is suggesting to remove limits on memory, quite the opposite - limit it more and make it scale with GCL.


  • Culture

    It isn't an "artificial cost". It exists. It is a real cost. You can affect the cost through the way you use memory. Therefore you should pay the cost.



  • Can somebody please provide a link with a good and full explanation how object design affects JSON (de-)serialization times/load and how that can be minimized?


  • Culture

    I don't have a link to a doc handy or anything. The short of it is that more objects cost more to deserialize.

    So as a trivial example, storing a path as 50 RoomPosition objects, i.e. 200 discrete values (the object itself, as well as x, y, roomName) is less efficient than coming up with a way to encode that path as a single string.

    Note that in that case you will still pay a cost when deserializing that path to its final form. The cost you're saving is the per-tick deserialize cost; you now have a new problem, of course, in writing an efficient mechanism for transforming that value back into something you can use. But you probably don't need every path you've cached, every tick, so even an inefficient algorithm for using the value is going to see a benefit over storing the raw RoomPositions in a large cache.

    (I don't even bother with this yet, I just store the raw RoomPositions. But I'm aware that that won't scale.)

    As for serialization, good news! That actually is free. It occurs after you return from your loop.



  • So the most performant approach would be to save it ALL as one large string and use something like an adress dictionary and areas having a fixed width or the like, just like hard drives are doing it .. !?
    Sounds fun. Hardest question is how to manage that adress dictionary. In a performant and convenient way.


  • Culture

    Yes! And if you go that far, you could use RawMemory and not even pretend to be using JSON. 🙂