Search Unity

Physics.Contacts GC activity

Discussion in 'Physics' started by fallFlat, Nov 23, 2015.

  1. fallFlat

    fallFlat

    Joined:
    Mar 26, 2014
    Posts:
    26
    While optimizing audio performance of our game Human: Fall Flat, I've noticed quite big GC allocations in Physics.Contacts. It leads to GC collect once a second, potentially skipping a frame in a game. I noticed this a while ago in other project on Windows Phone and thought it's WP specific. I believe this is related to allocating contacts array before passing to monobehaviors if no OnCollisionEnter/OnCollisionStay methods are defined it does not happen.

    Human will feature a physics based audio and we need to get collision information which is later processed to drive audio events. Already heavily optimized the code inside OnCollisionEnter and OnCollisionStay, but this GC issue is outside my code.

    We have one more GC allocation in GeometryUtility.CalculateFrustumPlanes but it's only 136B per frame, still it would be nice to have and overload where we could pass existing array.

    Is anyone else facing similar problems?

    physics.contacts.png
     
    Tymianek likes this.
  2. BennyChen

    BennyChen

    Joined:
    Jan 26, 2013
    Posts:
    3
    I'm experiencing the same problem, any one know a solution?
     
  3. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I had a small discussion with https://twitter.com/AnthonyYakovlev (don't know his forum handle) on alpha about this and he says there are plans. You can probably poke him on twitter to see if he wants to talk about it - he'd probably enjoy a stress test scene to work with...
     
  4. Sabrino

    Sabrino

    Joined:
    Aug 8, 2015
    Posts:
    35
    This is a pretty huge issue, it makes OnCollisionStay almost unusable. Is there any news on this?

    We just got NonAlloc versions of RayCastAll etc., it would be really great if we could get a NonAlloc version of OnCollisionStay, at the moment the garbage generated is just too much.

    Another big improvement would be if we could call OnCollisionStay on demand or selectively instead of all the time.
     
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    I can tell you that the 2D physics system has had this resolved for non-allocating callbacks for a while (since last year). Part of that work (retrieving contacts in a non-alloc way) is in the 2D experimental preview about to be released. The problem right now is that there's a change to the callback/event system that is holding this (2D) work up and the development of the 3D side of things as well. Essentially we can't change existing callbacks and/or introduce new ones until this work has been completed.

    Unfortunately, this is outside of the control of the physics teams right now but we've recently been into meetings to get this road-block resolved. It's a super important thing to resolve for both 2D and 3D that we're pushing hard against.

    Anthony and myself are well aware of the issues this is causing and want to get the new system in-place ASAP.
     
    PhilSA and hippocoder like this.
  6. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Thanks guys, it's a nightmare trying to raycast reliably when OnCollisionStay has everything we want, and it can be solved but it just isn't :/

    Often enough it's just one contact as well, we don't need many, but we need new data every fixed update... Seems crazy such a simple matter renders ..Stay() unusable.
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    It's certainly not limited to the Stay callback.

    It's two things that's causing this; the first is that the Collision(2D) type is a class and not a struct and the contact-points, whilst a struct, is within an array that needs to be created. Both of these end-up as garbage.

    We can't just change the Collision2D to be a struct as that would break backwards compatibility. There are plans to introduce a new callback that offers much more utility and passes back a new (struct) type with no allocations etc.
     
    ilmario, PhilSA and hippocoder like this.
  8. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    That sounds brilliant for all our projects (we use 2D and 3D physics, spending on title). I hate to ask but would it be possible these (3D and 2D) changes make it in before Unity 6?
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    Absolutely, this isn't some far-off research or anything crazy like that. As far as I'm concerned, they'll be in the Unity 5 release.
     
    PhilSA and hippocoder like this.
  10. Sabrino

    Sabrino

    Joined:
    Aug 8, 2015
    Posts:
    35
    That sounds good, thanks for the update. Personally I am working with 3d, and as hippo said the ability to limit the contact points stored on every call would be very useful as well.

    Non allocating struct sounds perfect. Really looking forward to the new callbacks.
     
  11. DragonSix

    DragonSix

    Joined:
    Jul 2, 2013
    Posts:
    37
    At least 1KB of allocation per frame and per object that uses the callback. It quickly gets ridiculous. You need to do something.
     
    Last edited: Jun 23, 2016
  12. fzd

    fzd

    Joined:
    Jan 30, 2013
    Posts:
    41
    Thanks for looking at this and appreciate it's dependent on other work going on.

    Is there any updates or a timescale?

    With heavy Physics it's killing the FPS:

    Capture.PNG
     
    hippocoder likes this.
  13. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926


    I see this is scheduled for 5.5

    Hopefully the GC alloc fix will have been done alongside that PhysX upgrade? (one can dream, right?)

    Also...



    I'd really like to know if we'll get something like "UseFullKinematicCollisions" for 3D rigidbodies?
     
    Last edited: Aug 22, 2016
  14. Martyn96

    Martyn96

    Joined:
    Apr 8, 2016
    Posts:
    5
    @MelvMay This issue still exists in Unity 5.5.2f1, can you confirm this will be fixed in Unity 5.6?
     
  15. Lamaseed

    Lamaseed

    Joined:
    Jan 21, 2017
    Posts:
    2
    So anyone know if this is fixed in 5.6 now that it is released?
     
  16. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
  17. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    @MelvMay - i see you are still alive. is this thing actually getting fixed or is it time to roll our own physics?
     
  18. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    You are always free to roll your own physics but in the meantime there's this: https://forum.unity3d.com/threads/non-alloc-and-filtered-collision2d-getcontacts.469613

    Also note that I did have a branch which completely rewrote the 2D physics handling and removed all GC activity (as I stated above) however it made changes that were not allowed (yes, Unity is big and things need to be validated and everything needs to work together). I ended-up putting all the contacts rewrites in there but without the new non-GC contact callbacks. If it were simple then it'd be done already.

    That work was on hold until "another system" was implemented. It has been frustrating as that other system has still not surfaced and my hands are tied. I recently made a push to get this resolved and as I posted in the thread above, we've got a meeting to discuss the next step for this which has to happen soon.

    The scripting backend has seen much love recently and AFAIK, we're ready to move forward with a new super fast event system. This'll not only solve the GC issue but also make script callbacks much faster.

    When I was testing my multithreading 2D physics work where I had half a million collisions being processed, by far the most dominant portion was the script callbacks. I ended-up disabling those completely just so I could work correctly. This is another aspect that should be solved.

    If we didn't care about backwards compatibility then we could just change "Collision" and "Collision2D" to be structs and not classes. That combined with the lazily created "contacts" property (which you should not use) and the new "Collision2D.GetContacts()" would mean zero GC activity.
     
    Last edited: May 9, 2017
  19. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    Users don't really care about excuses, but we do need to make hard decisions that will affect our development schedules. In this case, I don't have much confidence that it will ever get fixed. It's unfortunate because this is the only GC in my game, i am sure others are in the same boat.

    I am also sure that we would be ok if you bypassed the backwards compatibility excuse and made parallel API, like the raycast stuff, something along the lines of OnColisionEnter2DNoAlloc().
     
  20. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    Excuse? You mean reason right? If you want to negative-spin it then sure, lame excuses.

    All I can give is transparency on what is currently happening as I always have. We all have dependencies on something. If this is not good enough for you then there is little else I can do. I could've easily not provided you with the information despite your tone but I am here doing what I can do given the restrictions. There is frustration on both sides.

    Whilst that might sound good for you, it's not something that can just be thrown out there. Unity is undergoing a lot of changes with major refactoring under the hood and removing tech-debt is extremely important. The physics callbacks are tech debt and require the new fast event-based system in-place before we can remove it.
     
  21. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    Melv, you are 100% correct. I am just frustrated, and I can see you are too. I am sorry for being a dick.

    What we should do is discuss here, so others that are also frustrated, when searching for help, have some ideas. One thing you mentioned, and is certainly a good idea, is polling.

    On the low-end android device, I see around 5ms per frame spent in overhead polling 125 rigidbodies against maybe 250 total rigidbodies in a busy scene via GetContacts with contact filters. these scenes are not the norm, but they do happen sometimes.

    5ms is more than i would like to spend doing anything in a frame. Obviously all 125 rigidbodies are not colliding every frame, one would assume a callback method is more efficient.

    But, as you said the callback method itself must have some overhead. assumptions are dumb. balancing costs of polling fixed cost vs garbage doom frame, perhaps polling does make more sense? I am running some benchmarks now to find out.
     
  22. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    all 2d rigidbodies.
     
  23. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    I should also add all of the colliders are CircleCollider2D, one per rigidbody, nothing fancy. good old radius checks.
     
  24. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    It's hard to say which is more efficient but I can say, the existing callback on a script method which can potentially happen four times per collider pair (ColliderA, ColliderB, RigidbodyA & RigidbodyB) can become very inefficient.

    Likewise, checking for all contacts (GetContacts) can become inefficient, depending on how it's used just as doing almost anything could.

    If you're looking for using GetContacts polling to replace the collision callbacks then the new "Collision2D.GetContacts()" (https://twitter.com/melvmay/status/861222263009443840) will be much faster as it only returns the specific contacts for that collision however that's only useful in the collision callback which will still leak a tiny bit due to the "Collision2D" type being a class but the majority of leak from "Collision2D.contacts" has gone. At the same time there's a new "Physics2D.GetContact(Collider2D, Collider2D, ContactPoint2D[])" which is super efficient, much more efficient than (say), asking for all contacts for a specific Collider2D.

    The meeting we're having is for us to learn how a new fast event-system within Unity can be used for 2D & 3D physics. When I know, I can pass the info along to anyone interested.

    The shift for 2017 is to provide as much low-level access to data and functionality as is possible over creating "big thing" features as I hope you agree is represented by the road-map stuff I added here: https://unity3d.com/unity/roadmap

    Additionally, we're going to try to keep 2D & 3D physics in sync where possible and where it makes sense.

    Existing functionality was designed very much as fire-and-forget but that leads to it also being easy to shoot yourself in the foot. New functionality is going to be much more low-level allowing more and more simulation control to be done in managed code leading to more control for you and more possiblities for asset store developers. This leads into the further future when we're looking at how a C# job system can be utilitised.

    That low-level exposure of 2D physics is going on right now. I am working on C# low-level primitive shapes, job-based query batches & new low-level primitive intersection tests.

    You are correct in that I am slightly frustrated in that I inherited some legacy tech-debt stuff such as the collision callback GC problems and given that everything that has gone out in the last year is focused on non-allocation, this is a thorn in my side as well as the 3D physics team who suffer the same problem.
     
  25. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    Also, are contacts cached when resolving a collison, or is a Collider2D.GetContacts() poll testing for touching on-demand? there's that nagging worry of missing high-velocity/highly-elastic collisions. when i get a chance i should write something that compares Collider2D.GetContacts()'s results with a circlecast and verify.

    Is there a way to get all of the collisions that happened in the last frame into a pre-allocated array in a single call? this would be ideal. i want to know about collisions, not necessarily contacts. Magic trampoline rides aren't free. Instead of hundreds of API calls, it's better to make zero or one.

    In my case I do not need the actual contact points. I just have a bunch of CircleCollider2Ds and want to know if they bump into each other..

    circleA - many of these
    circleB - often more circleB than circleA, but not always. passive.

    all i need to know is if any circleA was in a collision with any circleA or circleB, and if so, who was involved. don't care if circleB hits a circleB.
    for this i have been using layermask and callback that quickly looks up whatever data I need using the collider2d's instanceId as a key. that's all i need, is some key identifying who is colliding with whom. no points or anything else. relative velocity would be nice, but i can work all that out pretty quick.

    anyway, this works pretty good, callbacks aren't called all that often, certainly not even once a frame. if it wasn't for that gc...

    i have also been testing this, only polling cirlceA, only when they are in a state that matters. worst case is currently around 125 calls per frame. on PC, that's not too bad, but on android it adds up quick.

    UnityEngine.Profiling.Profiler.BeginSample("poll collision");
    int colliderCount = myCollider2D.GetContacts(contactFilter, colliders);
    UnityEngine.Profiling.Profiler.EndSample();

    upload_2017-5-10_14-42-13.png

    Here we can see the overhead of just calling that function 133 times was over 3ms (and the profiler node overhead, sure). the function itself only took 1.6ms. This is the overhead I am trying to avoid.
     
  26. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    I should add that that cost fluctuates wildly. in this frame it may have had some collisions to report:

    upload_2017-5-10_14-52-56.png
     
    Last edited: May 11, 2017
  27. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    The physics system receives contacts from Box2D and they are cached. These are used for all "GetContacts" and "IsTouching" calls. There's no collision detection going on in these calls. It'll be faster if you set the "contactFilter" to be "ContactFilter2D.NoFilter()", something the overload of "Collider2D.GetContacts()" that takes no ContactFilter2D does for you.

    There isn't although that would be possible to set up and is an interesting idea I've taken note of.

    I can only presume you mean per fixed-update; doing this per-frame is an enormous waste of resources as contacts only change during the fixed-update.

    How many contacts are we talking here in total in the world and how many typically are you returning in each of these calls? Do you have a simple reproduction project you could share so I could profile it here as a comparison?
     
  28. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    Thanks for the clarification. GetContacts() should be more accurate than a simple circlecast then.

    I am now using your excellent "Physics2D.autoSimulation = false;" to use unity like most other game engines, where physics is run exactly once per frame. I call Physics2D.Simulate(Time.deltaTime) on the update pulse. This makes my game run hilariously smoother- less jitter, fewer frame drops, and more consistent than using autoSimulation and FixedUpdate.

    most frames would have 0 contacts. there are up to 255 CircleCollider2Ds in the world, but they are usually not touching each other. I do not have a simple project set up.
     
  29. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    One is not more accurate than the other. GetContacts gets existing contacts whereas CircleCast is speculative contacts. Accuracy is the same.

    Running physics per-frame gives you inconsistent results for the same reason that a single physics update of 1 second gives you different results than a hundred updates of 1/100th sec but if it works for you then that's fine. Note that it'll be more expensive doing it this way.

    You might as well turn off interpolation for all Rigidbody2D as there is no interpolation if you're updating every frame.

    If you have 0 contacts most frames then I am amazed it takes as long as you say to get zero contacts.
     
  30. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    If you can keep your framerate consistent, this is not much of a real issue. We're looking for 'good enough for a player to have fun' not full-on determinism here.

    In terms of smoothness, I would rather update once a frame than ever have to worry about a spikey frame caused by running sim more than once. Updating less than once a frame causes visible jitter, so what you want is to sim once a frame.

    And then you get the sample aliasing that happens when you run the simulation clock (FixedUpdate pulse) separate from the rendering clock (Update pulse). This aliasing is also visible as jitter. Nothing is rendered truly fluidly, there is always positional and rotational harmonic noise in the signal due to the fluctuating temporal difference between sampling and rendering. Anyone who has done a bunch of audio dsp stuff will tell you about some guy named Nyquist. To reduce this, you run the sim clock as close as you can to the render clock to get a more analog response. Which I am a lot closer to now.

    Even if it is slightly less accurate when the GC doom frame strikes, it is far more pleasant for the player to do it this way. And my framerate has not declined by doing it this way. If anything it's improved because it never sims more than one frame in a frame.

    Thanks for the tip. I will try that.

    Me too. That was profiled on our minspec android. Occasionally there some contacts, but usally not. In the graph view, that frame had one of the 135 calls to GetColliderContacts() block for many ms. It was one spikey call rather than all of them... regardless, it shows that paying for the ticket to ride the magic trampoline to unity land 135 times is not worth it in my case.
     
    Last edited: May 11, 2017
  31. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    darn, interpolation was already off. was hoping for an easy win. :D
     
  32. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    to be clear, interpolation would help if i wanted to run the physics at less than 30hz... but running that slow introduces latency, which is no fun for anyone. it does help filter aliasing noise, but adds it's own distortion error, especially when extrapolating. but the real big thing is running 2 frames+ to try to catch up on a slow device just makes everything worse. might as well just run physics once a frame and be done with it.
     
  33. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    I do understand all the problems involved. In the end, if the loss of accuracy is good for you then it's good is all I was saying. Not everyone does.

    No, interpolation is used when your framerate runs at a higher frequency than the physics which it typically does. During each frame, the body position is interpolated from the last body position to the new one so acting like you were updating physics each frame but without the cost.

    You seem to be using the term "frame" interchangably with the frame render and the fixed update. Unity never runs "2 frames+ to try to catchup". It will of course, during the fixed-update interval only, run more than one simulation of fixed-update delta if its behind. This may be of course what you were saying but using the term "frame".
     
  34. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170

    A/B test 2d physics with let's say a spring joint with physics running at say 80% of rendering framerate with interpolation against Simulate(Time.deltaTime) with no interpolation and the difference is astounding. the second is incredibly smoother. The cost is one sim per frame, and you don't pay for interpolation.
     
  35. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    Sounds like it's perfect for you!
     
  36. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    yeah Melv, this is seriously the greatest improvement to rendering physics with fidelity my game has seen in a while. I'm stoked on it.
     
    Last edited: May 12, 2017
  37. SiliconDroid

    SiliconDroid

    Joined:
    Feb 20, 2017
    Posts:
    302
    RE: Physics.Contacts GC activity.

    On Android
    my game shows Zero GCAlloc while OnCollisionStay is firing.

    In the editor (In Windows or Android player settings) it still shows 140b per OnCollisionStay.

    I know OnCollisionStay is firing because I'm analyzing contact point/s to make spatialized metal scrape sounds as a vehicle scrapes buildings, I was watching the deep profiler: zero GCAlloc.

    Also noticed reading GameObject.name or tag also gave no GCAlloc on Android device, it does in editor.

    The GCAlloc in android device profiler seems to be accurate, I'm a little sloppy with some less frequent transient events and it was as expected.
     
  38. Steamc0re

    Steamc0re

    Joined:
    Nov 24, 2014
    Posts:
    144
    This seems like classic "Bus Stop" problem; you are waiting for the bus, but it's late and you aren't sure if you should just start walking. The longer you wait, the more you don't want to lose the time you've already waited in case the bus comes right after you leave, so the longer you stay, the harder it is to leave.

    This thread is over a year old and backwards compatibility was trying to be preserved, but here we are later and GC on collision callbacks is still a problem, but hey, at least everyone didn't have to rewrite code to take advantage of a better system... Are we going to leave the bus stop soon?
     
  39. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    But three will come along at once.
     
    SiliconDroid likes this.
  40. JustAnotherDude

    JustAnotherDude

    Joined:
    Oct 28, 2013
    Posts:
    279
    They should have used the 2017 release to fix it... While they decide not to fix, we have to look at this stuff...

     
  41. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    not sure if this has been mentioned yet - but I only see Physics.Contacts GC allocs in the editor; not in builds

    This appears to be similar to GetComponent creating garbage in editor if the component isn't found, but not in builds. It's because it generates editor-only warning message strings internally
     
  42. JustAnotherDude

    JustAnotherDude

    Joined:
    Oct 28, 2013
    Posts:
    279
    Interesting, but that profiling pic I posted is from the editor attached to the android running the game, so we can be safe to ignore all this GC if the profiler is not attached ?
     
  43. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I'm not going to assume. Contacts seems like an area that should generate garbage because we aren't passing an array for Unity to fill.
     
  44. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235


    This still has not been fixed as of 2018.2 either, unfortunately. I am having a huge issue with it when trying to use PuppetMaster in my game, which is killing me as PM is one of the most major parts of the game.

    Is there any update on this at all? : \
     
  45. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    We will see after 2018.3 since the version of Physx changes there.
     
  46. herb_nice

    herb_nice

    Joined:
    May 4, 2017
    Posts:
    170
    It's unity's interface between unity and box2d / physx that is creating the garbage allocations, so bumping physx will probably do nothing.

    The GC from contacts has been the ONLY gc in our project for years at this point. it still causes GC frames.

    This is 2018.2.5f1 connected to a player build, it generally allocates in increments of 7k. I have seen it spike up to over 100kb in a frame similar to that screenshot above:

    upload_2018-9-9_10-22-37.png

    I have zero faith that unity will ever fix it, or provide an alternative, non gc interface for acquiring contacts. There was some discussion here a few years back that sounded like they were thinking about fixing it, but there certainly has been no measurable action. Future projects will consider alternative technologies.
     
    densy07 and hippocoder like this.
  47. artics

    artics

    Joined:
    Sep 17, 2013
    Posts:
    8
    2018.2.13f1
    These tiny spikes freeze FPS
    upload_2018-10-21_23-58-16.png
     
    herb_nice likes this.
  48. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    One can only hope for allocation free contacts one day.
     
  49. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,428
    The good news is that I've actually nearly completed work for both 2D & 3D. Just some docs/tests/testing to complete. I can provide more info if required but yes, goodbye collision GC allocs.
     
  50. fallFlat

    fallFlat

    Joined:
    Mar 26, 2014
    Posts:
    26
    Still eagerly waiting for this, keep us posted with the details!