Infestation:PlaceBlobs causing massive slowdown [prolife]
Swatinem
Join Date: 2012-10-29 Member: 164362Members
When I was playing today on *tram*, I noticed than whenever i was near shipping/observation, my frames halved. From the usual 50-60 fps, it went to ~20fps.
When I left the area (back to hub), the frames returned to normal.
So I did a quick profile: <a href="http://cloud-2.steampowered.com/ugc/577849604472451369/B54EB906A9747018D408BE9BB4C696E7711B6A57/" target="_blank">http://cloud-2.steampowered.com/ugc/577849...C696E7711B6A57/</a>
So the „dynamic“ in Infestation means the blobs are generated on the fly, most noticeable when you are comm or when you respawn.
If I’m reading the profile correctly, the Infestation seems to be generated on every frame, slowing the game to a crawl. It also seems to do a GC directly in Infestation:PlaceBlob, for whatever reason.
I should have probably done a second profile screen as well, as only half of the GameClient:Update time is visible on screen :/ Don’t know what else is going on there...
Will try to come up with a better profile once I hit this bug a second time.
When I left the area (back to hub), the frames returned to normal.
So I did a quick profile: <a href="http://cloud-2.steampowered.com/ugc/577849604472451369/B54EB906A9747018D408BE9BB4C696E7711B6A57/" target="_blank">http://cloud-2.steampowered.com/ugc/577849...C696E7711B6A57/</a>
So the „dynamic“ in Infestation means the blobs are generated on the fly, most noticeable when you are comm or when you respawn.
If I’m reading the profile correctly, the Infestation seems to be generated on every frame, slowing the game to a crawl. It also seems to do a GC directly in Infestation:PlaceBlob, for whatever reason.
I should have probably done a second profile screen as well, as only half of the GameClient:Update time is visible on screen :/ Don’t know what else is going on there...
Will try to come up with a better profile once I hit this bug a second time.
Comments
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> // Get a uniformly distributed point the circle
local x, z
repeat
x = random(-maxRand, maxRand)
z = random(-maxRand, maxRand)
until x * x + z * z < maxRand * maxRand<!--c2--></div><!--ec2-->
which is pretty dang scary actually, since in theory this could hold up indefinitely. I understand the intention (to keep it within the radius of the cyst) but it shouldn't be done as a bunch of attempts until it's within the circle, it should be done using something like this:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local x, z, t, r
t=2*pi*random(0,1)
r=random(minRadius,maxRadius)
x=r*cos(t)
y=r*sin(t)<!--c2--></div><!--ec2-->
this will give you a random point in the circle in one calculation, instead of in somewhere between 1 and infinite calculations.
not sure how Lua does sin and cosign though. those can potentially be intensive to calculate if you're doing something like a taylor series. In the past I've used just a value index to look up the potential values of sin and cosign and it worked out fairly well. I'm sure NS2 would have a well established way for calculating sin and cosign exactly, but it might also be worth it to have a less precise but faster version for scenarios like this.
a slightly different take is <a href="http://stackoverflow.com/questions/5837572/generate-a-random-point-within-a-circle-uniformly" target="_blank">here</a> that should give a uniform randomization, as I believe mine will be more concentracted at the center by making the following tweak:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local x, z, t, r, u
t=2*pi*random(0,1)
u=random(minRadius,maxRadius)+random(minRadius,maxRadius)
if u>maxRadius then r=u-(maxRadius*2) else r=u
x=r*cos(t)
y=r*sin(t)<!--c2--></div><!--ec2-->
Still does not explain why it usually runs without problems but why it was triggered a lot more in this particular situation.
And not those „i go into the room and its slow for a frame“ but constant slowdowns when I’m in a certain area.
20ms combined is waaay too high just for infestation. I’m also wondering why it causes such long GC pauses.
<a href="http://cloud-2.steampowered.com/ugc/578976070515724945/804212EBBCDEE12A255F444E8267F52ECC7C5086/" target="_blank">http://cloud-2.steampowered.com/ugc/578976...67F52ECC7C5086/</a>
PlaceBlob is really slow, but also UpdateBlobAnimation is slow. Both add up 18-19ms (including gc).
This is half of the total frame time. Thats really not acceptable :(
The problem seems to be in GetBlobPlacement <a href="http://cloud.steampowered.com/ugc/578976070551536872/3EF5730977E5324B1D22B8E635E7553F449DC0F2/" target="_blank">http://cloud.steampowered.com/ugc/57897607...E7553F449DC0F2/</a>
So, here I have high CreateModelArrays numbers: <a href="http://cloud.steampowered.com/ugc/578976070551528321/39ED2B5A7B92107F7D7F2F654B69A61FC1A1FB2F/" target="_blank">http://cloud.steampowered.com/ugc/57897607...69A61FC1A1FB2F/</a>
High minimap drawing numbers: <a href="http://cloud-2.steampowered.com/ugc/578976070551539234/A3DFC5F2D129A6EB673657763F92A0A2C82C9985/" target="_blank">http://cloud-2.steampowered.com/ugc/578976...92A0A2C82C9985/</a>
The console commands “debugblobs†and “debuginfest†are also nice to play around with, but with “debuginfestâ€, the fps goes down to below 1fps, haha.
-> <a href="http://cloud.steampowered.com/ugc/578976070551512100/14F9A0F207E5AC7043EC1490B92A88B052E0FF10/" target="_blank">http://cloud.steampowered.com/ugc/57897607...2A88B052E0FF10/</a>
So, in conclusion:
We have
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> // Maximum number of blobs to generate in a frame
_numBlobsToGenerate = 100
[…]
numBlobGens = math.min(_numBlobsToGenerate, self.numBlobsToGenerate)
self:PlaceBlobs(numBlobGens)
[…]
local numBlobTries = numBlobGens * 3
for j = 1, numBlobTries do
[…]
local position, normal = GetBlobPlacement(x, z, xRadius, hostCoords)
if position then
[…]
numBlobs = numBlobs + 1
if numBlobs == numBlobGens then
break<!--c2--></div><!--ec2-->
Well this is quite complex code, but I kind of get the problem here:
The code (tries to) generate 100 blobs per frame.
For each blob, it *tries* 3 different random placements, hence the number of calls for GetBlobPlacement is maxed at 300.
The problem is that the placement might be invalid (I guess it has to do with level geometry?) and it does not place a blob at all and the same thing continues the next frame.
I think thats why I saw a constant slowdown when I roam around specific areas of a map. Seems like GetBlobPlacement returns an invalid position, and the code retries placement over and over again every single frame, leading to a constant slowdown.
Reading the GetBlobPlacement code further, a correct placement would need 4 TraceRay traces for a correct placement (and anything from 1-3 for an invalid placement). On the supplied screenshot, we have 535 TraceRay calls for 300 GetBlobPlacement calls, which is a rather poor hit rate.
This whole “get a random point, check if it can be placed on the level geometry, otherwise keep trying†concept seems to be quite bad.
Why not do the following:
* get the simplified level geometry that should be infested
* place blobs *on that geometry* instead of at a random point which does not touch the geometry at all.
Also regarding the minimap:
Why not use *one* texture for infestation overlay.
When the infestation changes, this texture is refreshed, otherwise it does not need to be. That texture can also be composited in such a way that the blips do not go over the edge of the minimap.
For the marines, that texture would be masked using a “line of sight†texture.
I think that would look better and perform better than the current method of drawing hundreds of blips on the minimap.
It would be awesome to get some feedback from the devs regarding this stuff?