PTR Changelog 2016-09-29
-
> 1000 flags per GCL means someone with GCL 30 can create 30,000 flags. 30,000 JavaScript objects is… a lot.
Then I think finding a way to allow lazy loading of the flags people actually want, rather than loading them all, or a way to cache them as n00bish suggests is the way to go. I rarely need all of the flags, so I shouldn't have to pay for all of the flags when I need one.
-
To re-iterate apparent issues server-side:
- Massive flag names
- Massive amounts
- Parsing/creating flags costs
_____________________________________________________________________________
Issues on player
- Sudden massive increase in CPU, which can't be altered
- Sudden change in strategies requiring massive reworks in big player code bases
- Some names might be cut off
_____________________________________________________________________________
Proposals
- Add possibility for own implementation to parse flags for the game-engine
- Give more CPU to circumvent the change, this doesn't punish players using the flag system
- Add a CAP on the max flags per GCL (proposed 800~1000 per GCL) I only need 40 flags per GCL personally
- Add separate Memory section for flags, max 50kb on flags, without CPU hits, or 2kb per gcl
- Slowly work to remove flags, and make everything memory based, but provide methods of "pinging" on the map.
-
"1000 flags per GCL"
@ All. Also take into consideration that from a scaling perspective we should assume everyone use all that is at its disposal.
(If not, it will only be an issue later)
So we are talking about 15 to 30 millions flags to serialize deserialize every tick.
This looks like a lot...
-
All. Also take into consideration that from a scaling perspective we should assume everyone use all that is at its disposal.
Exactly! This is where the CPU cost approach makes more sense.
Add separate Memory section for flags, max 50kb on flags, without CPU hits, or 2kb per gcl
What about 10,000 flags static limit without depending on GCL? Like the memory limit which is also static. When you outgrow it, you have to consider other more optimized ways to markup your room, using Memory probably.
-
Artem, to get a sense of scale for us, what is the current average of amount of flags per GCL?
GCL 1 = 20 flags
~
~
~
GCL 28 = 4000 flags
Something like that.
-
I'm OK with 10.000 flags, purely because it fits.with my code (only 1000 flags)
My statement for:
> max 50kb on flags, without CPU hits, or 2kb per GCL
was that, as a player, makes you think about the impact of flag usage early on, and you can see how much flags use. The maximum should still be reached at GCL 28, just like the CPU.
-
Since the new Flag() part is the problem, using a memoized getter to lazy initiate the flags could help with the CPU issue. Such as below:
serializedFlags.forEach(flagRoomData => {
var data = flagRoomData.data.split("|");
data.forEach(flagData => {
if(!flagData) {
return;
}
var info = flagData.split("~");
var id = 'flag_'+info[0];
Object.defineProperty(register._objects,id,{
get: function(){
delete register._objects[id]
return register._objects[id] = new globals.Flag(info[0], info[1], info[2], flagRoomData.room, info[3], info[4]);
}
})
})
});
-
I still think it's insane that you're creating each flag for each tick. I think exploring the approaches n00bish and others are talking about makes more sense, because most people are not accessing every flag every tick. I think the limits being put in place are trying to solve the wrong problem. Even if limits are put in place it makes sense to optimize this purely from a "lets not waste resources" standpoint. If this has to involve API changes that's okay as long as we can see them coming.
That being said I've now left the "anger" stage and entered the "bargaining" stage. How about 15k flags?
-
Artem, to get a sense of scale for us, what is the current average of amount of flags per GCL?
I don’t have such a calculation at hand, but here is another one:
1 percentile - 613 flags
2 percentile - 312 flags
5 percentile - 140 flags
10 percentile - 54 flags
20 percentile - 15 flags
50 percentile (median) - 8 flagsSince the new Flag() part is the problem, using a memoized getter to lazy initiate the flags could help with the CPU issue.
This is the same CPU-cost-based approach, since the getter will be called in the user CPU space. If you iterate through all of your flags, you will be paying for this instantiation in full every tick.
-
Another thought is that if you are limiting flags you could add another structure, called a Landmark, which is like a flag but is attached to the Room object instead of the game object.
The landmark structures can have the CPU cost you're talking about but with no limit in number. Since we can load them per room we can spread that cost out over multiple ticks ourselves by interacting with those landmarks once every X ticks or something.
This would make a limit on Flags much more palatable as it would still give people who do automated layouts a way to do so. A 10k limit with the promise of landmarks on the roadmap would work. People will naturally migrate to landmarks as they get closer to the flag limit.
-
For the record I never iterate over all the flags.
-
Yes, it would be the same cost IF the user iterated over them all, but, if the user say, called Game.flags.xyz, it should only initiate xyz and not all of them. It would only be in cases like lookAt or iterations that would trigger them all.
I am still all for the 50-60 char name limits, I'm just trying to help out on the related core issue
If I'm not mistaken, this would also end up user side, but, would give the user much more controll over how much it costs.
-
Another thought is that if you are limiting flags you could add another structure, called a Landmark, which is like a flag but is attached to the Room object instead of the game object.
The landmark structures can have the CPU cost you’re talking about but with no limit in number. Since we can load them per room we can spread that cost out over multiple ticks ourselves by interacting with those landmarks once every X ticks or something.
This would make a limit on Flags much more palatable as it would still give people who do automated layouts a way to do so. A 10k limit with the promise of landmarks on the roadmap would work. People will naturally migrate to landmarks as they get closer to the flag limit.
Well, now you are offering an alternative, and I like it! We have to think about it a bit more though, but it might be the path that leads to the solution we’re looking for.
-
It would be great if we had a way of iterating flags without causing the objects to instantiate. That would still disallow a few ways people tend to use them now, but would at least open up another area.
IE: I only use a handful of flags dynamically. Most other flags are objects that really don't need to be checked every tick. Now I have to stop using flags for everything but the periodic checks because I have to pay the entire deserialization cost by touching one of them. (I don't have many flags; just planning ahead).
IE: an iterator or array containing flag _names_, separate from a function like Game.getObjectById() that gives you the whole flag object back.
I understand that some people are checking properties of flags on every tick and there isn't much to be done there. Caching or object reuse would help, but it seems like our instances aren't very sticky so I'm not sure how that would play out in reality.
As an aside: It sounds like you're having a lot of systems issues in recent months. Is there any way at least one of us who does this professionally could help with a few hours of labor? I'm well familiar with being on the other side of something with performance issues and having people armchair-narrate how to fix them without a full understanding of the problem.
However I've also been pulled in many dozens of times by random (very large) companies and made pretty large impacts by dealing with easy low hanging fruit. If it helps smooth things out I'm sure at least someone would be open to it (I could throw a few hours or days at it).
Thanks
-
Few notes on Landmarks-
- They should work just like flags as far as placement and removal goes- the closer the APIs are to each other the easier it will be for people to use them with existing code.
- Unlike flags they would require room visibility, since they are attached to the room object.
- They should *not* be included by default in the look* functions, since that would force them to get created each tick and the whole point is that they should allow us to only have to access them when needed.
-
On the bottom of page 1 of this thread, dissi suggested something I wanna repeat so it doesn't get lost:
I think if we can emit events for the game to display:
Game.rooms['someRoom'].displayIcon(SomeRoomPosition, COLOR_BLUE, COLOR_RED, "path.to.memory") // Maybe public/private? vision required!
A lot of people would be happy. Of course you can still choose to use the flags, but at a cost.
I was wondering for quite some time if this would be a possibility: adding methods that let us influence the game rendering, like drawing an icon at a certain position, a line between 2 positions, etc - just to visualize what our scripts are doing, for debug purposes or whatever. so far I've been using flags for that, but that never felt quite right. i don't need actual persistent objects there, i just want some visuals.
-
I just want to point out how much difference there is between the reaction from players now versus when this far more drastic change happened:
http://support.screeps.com/hc/en-us/articles/205193752-Important-change-CPU-cost-of-API-methods
It seems like the increased interaction is a good thing, coming up with more ideas. Hopefully there will be many more in the future, even on not such intense changes.
-
Artem, seriously, a great big thank you for maintaining the game. I know you need to push updates and security fixes and patches for balance and sometimes it either breaks our code or breaks our style of gameplay... and it makes some of us unhappy... but I can see that you have the future of the game's security, balance, and development goals at the forefront of your mind. Even if I don't like some of the changes as they roll out now, I look forward to playing this game from now into its future.
And thank you for noticing some peoples' utilization of flags as free memory (kilobytes per flag? wtf?) and making changes so that we don't collectively pay for those individuals' intelligent but generally taxing shortcut around memory utilization.
And thanks to the community for helping to come up with solutions for these issues when you feel like Artem is too heavy-handed on the updates. A shout-out to tedivm for not rage quitting and even putting some good solutions out there (landmarks? I can dig it). I say thank you because I don't have any solutions to the issues of flag usage, since I don't use any flags, therefore I'll kindly bow out of this conversation!
-
I was wondering for quite some time if this would be a possibility: adding methods that let us influence the game rendering, like drawing an icon at a certain position, a line between 2 positions, etc - just to visualize what our scripts are doing, for debug purposes or whatever. so far I’ve been using flags for that, but that never felt quite right. i don’t need actual persistent objects there, i just want some visuals.
It is a whole other take on this problem. We actually debated a thing like this before, some
RoomVisual
layer, where you can draw lines, rectangles, icons using the SVG-based API like that:Game.rooms.W1N1.visual.drawLine(from, to, 'red');
But it is just about UI representation, it will only be displayed in the game client as a separate visual layer on top of your room, your script won’t have access to this info, so it’s useless in terms of room positions markup.
-
Since the new Flag() part is the problem, using a memoized getter to lazy initiate the flags could help with the CPU issue. Such as below:
Another issue with this approach - you’re creating a separate getter function closure for each flag, so it is about creating thousands of closures, and they are also slow in V8. Our quick test shows that this approach is even slower than creating the
Flag
instance right away.