Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  High variance in ObiFixedUpdate performance impact
#11
(21-04-2020, 05:20 PM)josemendez Wrote: Internally, each solver spawns multiple tasks that get attended by a task scheduler (thread pool). Each actor is decomposed into a few tasks, but it does not matter if they are all under same solver or separate solvers as the tasks end up being exactly the same. So one solver does the same work as multiple ones, as it all comes down to tasks and a thread pool.

Just to test this, do you see any performance difference if you have the 50 particle rope and the 3 particle rope under the same solver, as opposed to having a solver for each one?

Yes - I just tested this hypothesis. 
Two pair of ropes under two solvers vs two pair of ropes under same solver. (A pair is still a rope with a loop on the end).

Two Solvers unity profiler data from build on Quest; https://easyupload.io/lm96le
Roughly 50 frames on average.

One shared Solver unity profiler data from build on Quest; https://easyupload.io/9qs98l
Almost stable lock at 72 frames.

(Edit; i also removed some disabled solvers from the updater, so there was only one solver in the updater compared to 8 solvers in the first test)

Exactly same amount of particles.

[EDIT]
The worst spike of obiFixedUpdate lies on 3.27ms on one solver vs. the >10ms on two.

It would be nice if you could confirm this, because I have to change a lot of my code base to put all ropes under one solver which is gonna take a long time.

[EDIT 2]
Maybe I could circumvent the redesign by putting each solver in its own fixed updater and turning those off instead? Currently they are all under the same updater.

[EDIT 3]
Can confirm disabled solvers in an updater still takes up a lot of resources apparently.
Reply
#12
That's really weird.

With one solver, all tasks get pushed to the pool at once. The two (or multiple) solver configuration pushes tasks for the first solver, then tasks for the second, then for the third... then waits for all these tasks to finish. So there's a slight difference in how tasks are pushed (since creating and pushing a task has very little overhead), but imho this does not justify the performance difference.

Only thing that comes to mind is that waking up threads in Quest is really expensive, and the time passed between pushing tasks for the first solver and tasks for the second solver is enough for threads to go to sleep. When the second solver pushes its tasks (almost immediately after the first one, but not at the same time), the threads have to be waken up and the tasks just lie there unattended for a long time, that varies depending on how many threads had to be woken up.

If this is theory is correct, using multiple Updaters won't have any positive impact. The only solution would be to use a single solver, then. Can you try the multiple updaters route, just to make sure?
Reply
#13
(22-04-2020, 12:03 PM)josemendez Wrote: If this is theory is correct, using multiple Updaters won't have any positive impact. The only solution would be to use a single solver, then. Can you try the multiple updaters route, just to make sure?

Can confirm. One updater per solver does not help performance at all.

Looks like I'll have to put all ropes under one solver, but then I'm forced to simulate all ropes at the same time. 
My current trick for performance was to just disable the solver when the rope physics wasn't needed but the rendering was.

It doesn't seem like there is any other way to stop the simulation of a single rope while keeping the rendering (of the ObiExtruder) - is there? 

Otherwise I guess I have to bake the mesh of all the different states my rope ends up in - which i really don't want to...

[EDIT]
Just tested with all ropes under one solver. Performance for ~430 particles (including Pooled so dunno what total simulated is) is at 40 frames.

Individually disabling the ropes' gameobject (in build) brings it back to ~65 frames for the two pairs I did the earlier tests on, but it looks like there is some performance lost by just disabling the ropes - like the solver is still iterating over ropes on disabled gameobjects. Is that correct?
Reply
#14
(22-04-2020, 12:03 PM)josemendez Wrote: That's really weird.

With one solver, all tasks get pushed to the pool at once. The two (or multiple) solver configuration pushes tasks for the first solver, then tasks for the second, then for the third... then waits for all these tasks to finish. So there's a slight difference in how tasks are pushed (since creating and pushing a task has very little overhead), but imho this does not justify the performance difference.

Only thing that comes to mind is that waking up threads in Quest is really expensive, and the time passed between pushing tasks for the first solver and tasks for the second solver is enough for threads to go to sleep. When the second solver pushes its tasks (almost immediately after the first one, but not at the same time), the threads have to be waken up and the tasks just lie there unattended for a long time, that varies depending on how many threads had to be woken up.

If this is theory is correct, using multiple Updaters won't have any positive impact. The only solution would be to use a single solver, then. Can you try the multiple updaters route, just to make sure?

Can you please confirm there is no build-in way (other than disabling the solver) to disable simulation/generation of mesh of a single rope without also disabling rendering?
Reply
#15
(27-04-2020, 12:23 PM)TheMunk Wrote: Can you please confirm there is no build-in way (other than disabling the solver) to disable simulation/generation of mesh of a single rope without also disabling rendering?

Hi,

- Disabling the rope component disables simulation for that specific rope, but still renders it.
- Disabling the rope renderer component disables rendering for that specific rope, but still simulates it.

Disabling the entire rope object disables both, of course.

So you can disable simulation by simply disabling the rope component. However, mesh generation/rendering is oftentimes much more expensive than simulation.

There's no way to disable mesh generation without also disabling rendering, as you can't render a mesh that does not exist.

Try using 5.3's rope decimation (http://blog.virtualmethodstudio.com/2020...ecimation/). This will adaptively reduce rope mesh resolution where possible, reducing rendering overhead. I'm attaching a updated ObiPathSmoother.cs component in case you're using 5.1 or 5.2, simply replace yours with this one and experiment with the decimation slider, it might be beneficial in your case.


Attached Files
.cs   ObiPathSmoother.cs (Size: 14.04 KB / Downloads: 0)
Reply