Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Performance degradation when using Collision callbacks in scripts
#1
Hello. I am using the latest Obi Fluid 7 with Unity 2022.3.43f1.

I noticed that when running a script with the following code while the Backend mode of the Obi Solver is set to GPU, performance deteriorates. Regardless of the processing inside the Solver_OnCollision function, simply registering a function as an event listener to .OnCollision causes a performance drop.

Example:
void OnEnable()
{
    if (solver != null)
    {
        solver.OnCollision += Solver_OnCollision;
    }
}

void OnDisable()
{
    if (solver != null)
    {
        solver.OnCollision -= Solver_OnCollision;
    }
}

private void Solver_OnCollision(object sender, ObiNativeContactList e)
{

}
However, when the Backend mode is set to CPU, the impact on performance is minimal.

Why does this happen?
Is there a way to use GPU Backend mode without causing a performance drop while still using this script?
Reply
#2
(01-03-2025, 12:08 PM)Cat3Man Wrote: Why does this happen?

It's simply a consequence of how GPUs work: they're designed to receive massive amounts of data from the CPU, process it and draw the results, but they're *very* slow at sending data back to the CPU. For this reason, the #1 rule when working with anything that involves the GPU is "what happens in the GPU stays in the GPU".

Obi uses asynchronous data transfers for this, in order to hide the cost using latency. However, if the data hasn't arrived after 1 full frame the CPU will wait for it to arrive, so if your frames are short then your bottleneck will inevitable become data transfer. Note this is not a Obi-specific thing: any operation that requires to bring data from the GPU into the CPU will be slow, another example is Unity's ReadPixels.

(01-03-2025, 12:08 PM)Cat3Man Wrote: Is there a way to use GPU Backend mode without causing a performance drop while still using this script?

Simply put, no. There's no way to send large amounts of data from the GPU to the CPU that doesn't incur a large cost. If you must do the simulation in the GPU, any further processing you need should ideally also happen in the GPU, using compute shaders. Also see Obi's manual about info on how to process particles using compute shaders.

(01-03-2025, 12:08 PM)Cat3Man Wrote: However, when the Backend mode is set to CPU, the impact on performance is minimal.

That's the expected result. When you subscribe to solver.OnCollision while using the GPU to perform the simulation, you're essentially telling the GPU "hey I'm going to need you to send all contact-related data to the CPU because I want to use it there, even though it will take a while". Even if you don't do anything with that data, it will be sent to you.

When using the Burst backend, simulation happens in the CPU and the contact data is already in the CPU so there's no need to do any data transfers: hence no performance impact. If you wish to process contact data in the CPU, doing the simulation in the CPU is the way to go. Note it also isn't a good idea to deal with potentially very large amounts of contact data in the CPU.

kind regards
Reply
#3
(02-03-2025, 11:49 AM)josemendez Wrote: It's simply a consequence of how GPUs work: they're designed to receive massive amounts of data from the CPU, process it and draw the results, but they're *very* slow at sending data back to the CPU. For this reason, the #1 rule when working with anything that involves the GPU is "what happens in the GPU stays in the GPU".

Obi uses asynchronous data transfers for this, in order to hide the cost using latency. However, if the data hasn't arrived after 1 full frame the CPU will wait for it to arrive, so if your frames are short then your bottleneck will inevitable become data transfer. Note this is not a Obi-specific thing: any operation that requires to bring data from the GPU into the CPU will be slow, another example is Unity's ReadPixels.


Simply put, no. There's no way to send large amounts of data from the GPU to the CPU that doesn't incur a large cost. If you must do the simulation in the GPU, any further processing you need should ideally also happen in the GPU, using compute shaders. Also see Obi's manual about info on how to process particles using compute shaders.


That's the expected result. When you subscribe to solver.OnCollision while using the GPU to perform the simulation, you're essentially telling the GPU "hey I'm going to need you to send all contact-related data to the CPU because I want to use it there, even though it will take a while". Even if you don't do anything with that data, it will be sent to you.

When using the Burst backend, simulation happens in the CPU and the contact data is already in the CPU so there's no need to do any data transfers: hence no performance impact. If you wish to process contact data in the CPU, doing the simulation in the CPU is the way to go. Note it also isn't a good idea to deal with potentially very large amounts of contact data in the CPU.

kind regards

Thank you for your answer!

I did not have enough knowledge about GPU and CPU characteristics. I will read the documentation again!
Reply