#Lane Player Optimisation
1 messages · Page 1 of 1 (latest)
How many iterations does this for loop generally go through then?
and please clarify what StartEaseX.Get(x) does
Some custom-written Easing library using IEaseDirective
Another question, is LaneStep a class?
Hmm okay maybe not so bad then. Its hard to identify what is contributing most to 9ms (did i read that right?)
public class LaneStep : DirtyTrackedStoryboardable, IDeepClonable<LaneStep>
how large is the list/array its looping over generally?
is that something I need to find out with a debugger
Erm if you dont even know then yea?
If its many thousands then thats important information
cache locality starts to be important and you may then need to start using a struct instead of a class
well I hated to attach debugger, because it doesn't keep my external editor config (rider) on restart, it either resets to VSCode (which I will consider uninstalling) or none
isn't a struct supposed to be done only on primitive types?
structs are value types vs a class which is a reference type
a list of a class is just a list of pointers, a list of structs however is a list of that struct object. This is good for cache locality because the objects are all next to eachother and this reduces "cache misses".
These are more advanced topics and are often harder to understand in managed languages like c#
If you know c/c++ or other native languages then this may make more sense
I feel like it depends on the intensity of the chart/level itself
because it's fundamentally user-submitted datas
Then stop and find out what data you are profiling with
Pretty important information to know
If you want others to help then make a thread in #1390346827005431951 instead ⚠️
I really barely understand what's happening >.>
the timestamp or the Verts/Tris?
this
Then how many itterations does this for loop run for?
for (float x = Mathf.Floor(progress * 16 + 1.01f) / 16; x <= 1; x = Mathf.Floor(x * 16 + 1.01f) / 16)
even dragged it to the part where it struggled for decent frametime
it works like a lerp
from quick steps, looks like, ~16-20 iterations
and how long is this "mesh lane step looper" section taking?
the section, if still too long add more markers to help finding the specific cause
I cant tell myself just yet
so 9ms for the marker, 7 to call AddLine() and 3ms for the actual list addition
Did it really run List.Add() 24k times???
I cant see the column headers
here but yeah youre right
well UpdateMesh is called 995 times in 1 frame which sounds pretty excessive
may just be that too many LanePlayer objects are updating at once
because the scene in question has ~30 ish lane in render :v
I have soo many questions, why are 900 updating in 1 frame? do they need to update each frame? is this only needed once on Initalisation?
(every white lines you see here is one individual lane)
(the designer really pushed it to the limit 😔 )
Entities may be good for you here if you need to process 900 of these a frame but depending on how the "mesh" is updated or changed you may be fucked either way.
Can you explain with more detail what LanePlayer update mesh is really doing?
(this is the entire function with the comments of explanations (before adding the profiler markers))
(sorry didn't bother pushing to a paste-site, since it's already uploaded here prior, so yeah)
to be updating the mesh and reuploading each frame 900 times is poor design and may not be viable
-# I mean, I'm just a maintainer, I didn't create this mess, honestly
Then what was the state of this performance wise before and what have you done and been tasked to do?
before I came in it was like barely optimised like the same chart would run in 10-15fps in most devices and most scenes don't even get a consistent 60fps draw
I switched the timestamp's identifier types from strings to enumerators
Replaced AddRange in f_AddLine to multiple Add calls
And have been refactoring the entire codebase (it's full of code smells prior)
LanePlayer's UpdateMesh is the most tricky to deal with so far
There are many general things you can do to get some free performance
first you can have 1 monobehaviour manager that manually "updates" these instances instead of using say Update/FixedUpdate 900 times
Secondly you can think more about struct usage to greatly speed up some loops that interact read and write to collections a lot.
Thirdly try to refactor away RemoveAt(0) because this will shift up ALL other elements, if required you should remove a large range in one go to perform that shift up once.
Also try to keep a local reference to Transforms used more than twice because there is a cost in retrieving the component via the .transform property
(This is because many functions and properties go to a native engine function and this has a small cost)
can you elaborate by 'keep a local reference to Transforms used more than twice'? Didn't quite catch that
//Do
Transform otherTransform = thing.transform;
otherTransform.position = Vector3.zero;
//Instead of
thing.transform.position = Vector3.zero;
May help here:
JudgeLine.transform.localPosition = (startPoint + endPoint) / 2;
JudgeLine.transform.localScale = new Vector3(Vector2.Distance(startPoint, endPoint), .05f, .05f);
JudgeLine.transform.localRotation = Quaternion.Euler(0, 0, Vector2.SignedAngle(Vector2.right, endPoint - startPoint));
won't it add an overhead from allocating an array/list on execute?
or would that outweight the current implementation's overhead itself?
(outweight might not be the right word, I meant it the other way)
I dont know were you got that from
removing a range is better because we can remove AND move up the elements after at the same time
if you remove an element in a list and its not the last, all other elements get shifted -1 to fill the empty space
1,2,3
remove 2
1,-,3
shift up
1,3,-
is this good enough?
//...
sr_TimestampRemove.Begin();
// Remove timestamps and position points when we already move past them
while (TimeStamps.Count > 2 && TimeStamps[1] < time)
{
_RemovingTimeStamps++;
_RemovingPositionPoints++;
_RemovingLaneSteps++;
}
//...
sr_MeshUpdater.End();
if (_RemovingTimeStamps == 64 && _RemovingPositionPoints == 64 && _RemovingLaneSteps == 64)
{
TimeStamps.RemoveRange(0, (int)_RemovingTimeStamps);;
PositionPoints.RemoveRange(0, (int)_RemovingPositionPoints);
Current.LaneSteps.RemoveRange(0, (int)_RemovingLaneSteps);
_RemovingTimeStamps = 0;
_RemovingPositionPoints = 0;
_RemovingLaneSteps = 0;
}
(dont ask why I'm casting to int, I was sleepy)
That while loop will never end, take a good look again
You need to re do it to calculate the amount of elements to remove in a better way
I guess I didn't catch it because it was updating in a coroutine
actually it's not necessary since it takes sub-1ms in profiler so I'm skipping that lmao >.>
For large lists it does matter
One thing that doesn't add up for me, is that this doesn't look like 900 line renderers.
dont think line renderers are used here (for some reason)
Well, whatever they're using, it doesn't sound like 900 iterations of this logic needs to run at the same time.