Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
DuplicateEditorMesh performance issue
#1
Exclamation 
Hi!

I was testing Curvy Spline and noticed that there is a huge amount of time spent inside DuplicateEditorMesh.Awake when you have a scene with a lot of object (and DuplicateEditorMesh component in the scene).

For example, for 770 DuplicateEditorMesh component in a scene, you'll get ~5000 ms spent in possibly doing nothing in that method.

Just because we are consistently make use of FindObjectsOfType<DuplicateEditorMesh>() and iterating through the result to find potential identical sharedMesh.

Do you have already encountered performance issue with that compoenent?
(well with inheriting components too, like CGMeshResource in my case).

If that Awake method is onlt here to catch duplicate in Editor, why not using the OnValidate and check the Event.type to catch Paste and Duplicate commands?

Also, instead of constently calling FindObjectsOfType, will it be more efficient to maintain (only in Editor) a list of Awaken component of that type?


Thanks for your shared experience!




Here is the DuplicateEditorMesh.Awake code:
Code:
        protected virtual void Awake()
        {
            if (!Application.isPlaying)
            {
                MeshFilter meshFilter = Filter;
                if (meshFilter && meshFilter.sharedMesh != null)
                {
                    DuplicateEditorMesh[] otherWatchdogs = GameObject.FindObjectsOfType<DuplicateEditorMesh>();
                    foreach (DuplicateEditorMesh dog in otherWatchdogs)
                    {
                        if (dog != this)
                        {
                            MeshFilter otherMF = dog.Filter;
                            if (otherMF && otherMF.sharedMesh == meshFilter.sharedMesh)
                            {
                                Mesh m = new Mesh();
                                m.name = otherMF.sharedMesh.name;
                                meshFilter.mesh = m;
                            }
                        }
                    }
                }
            }
        }
Reply
#2
Hi Guillaume

Thanks for reporting this issue.

I am having trouble reproducing the issue. I first just spammed the scene with tens of generators generating thousands of meshes, but the Awake method took less than 10ms. Digging deeper, I saw that the meshFilter.sharedMesh != null condition is always false, thus the FindObjectsOfType method is never called. This is because the sharedMesh  can be != null only if the object was reused, meaning taken from a pool. But pools are ignored in edit mode, and this awake code runs only in edit mode. So I am confused about how you managed to reproduce the issue. Did you modify Curvy's code? Please send me any information that would allow me to reproduce the issue.

About your suggestions to avoid calling FindObjectsOfType, they might be good solutions. The DuplicateEditorMesh was created by my predecessor, and I don't doubt that there are better ways to solve the issue he was trying to solve. I can give a better answer once I know how to reproduce the issue.

Thanks again, and have a nice day
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Reply
#3
I managed to reproduce the issue: it happens when you exit play mode, right?
I am looking into the issue. Will keep you up to date
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Reply
#4
Alright, I found a way to drastically reduce that Awake time, but there is still more I can do. Allow me to explain:

In my extreme test scene, it initally took 14 seconds to run all the awake methods. Only 2.5s of these 14 where spend on FindObjectsOfType. The remaining was used in other methods, a lots of it used in references comparison (== and != operators). This is due to how unity handles the == operator: it does not only compare references, but checks also if the associated Objects are destroyed or not, and if the instance ids match or not. I managed to reduce the need to call those operators, bringing the 14s down to 7s (The modified code is at the end of the post). That's good, but more can be done.
 
The solutions you suggested were focused on the FindObjectsOfType, and assumptions I need to verify (such as duplication happens only because of Paste and Duplicate events). If those assumptions are valid, your solution will help with the issue, but not solve the whole problem. I am thinking of another solution, based on using a HashMap to keep track of what meshes exist, but I need to dig deep into the DuplicateEditorMesh usages and raison d'être Smile to make sure I am not introducing regressions. I will delay this work for a later date. For now, I hope that the changes bellow will make the performance acceptable for your use case.


Code:
    public MeshFilter Filter
        {
            get
            {
                if (ReferenceEquals(mFilter, null))
                    mFilter = GetComponent<MeshFilter>();
                return mFilter;
            }
        }

        protected virtual void Awake()
        {
            if (!Application.isPlaying)
            {
                MeshFilter meshFilter = Filter;
                Mesh meshFilterSharedMesh = meshFilter.sharedMesh;
                if (meshFilter && meshFilterSharedMesh != null)
                {
                    DuplicateEditorMesh[] otherWatchdogs = GameObject.FindObjectsOfType<DuplicateEditorMesh>();
                    foreach (DuplicateEditorMesh dog in otherWatchdogs)
                    {
                        if (ReferenceEquals(dog, this) == false)
                        {
                            MeshFilter otherMF = dog.Filter;
                            if (otherMF != null)
                            {
                                Mesh otherMfSharedMesh = otherMF.sharedMesh;
                                if (ReferenceEquals(otherMfSharedMesh, meshFilterSharedMesh))
                                {
                                    Mesh m = new Mesh();
                                    m.name = otherMfSharedMesh.name;
                                    meshFilter.mesh = m;
                                }
                            }
                        }
                    }
                }
            }
        }
   


Feel free to ask me more questions about this subject or any other one.
Have a nice day
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Reply
#5
Hi _Aka_!

Thanks so much for your answers!

I should have added more markers to this Awake method, I was pretty sure that FindObjectsOfType was taking all the time, but I forgot all the things done in the Unity operators!
(but I think FindObjectsOfType will still garbage a lot. I still need to verify before saying wrong things again!)

The issue was happening when opening a scene, or switching back from play to edit mode.

I didn't modified Curvy heavily, just commented a line (and maybe that's the cause of the issue I realize that now, but I really think I have 700 legit DuplicateEditorMesh in my scene):


Code:
            if (firstChanged != null)
            {
#if UNITY_EDITOR
                DEBUG_ExecutionTime.Stop();
                if (!Application.isPlaying)
                {
                    // >>>>>>>>>> COMMENTED THIS LINE, because calling that from every Generator was showing it in the profiler, like a lot (I don't remember the duration)
                    //EditorUtility.UnloadUnusedAssetsImmediate(); //OPTIM is this necessary? It was added in changeset SHA-1: 4b04d2ea947cdb84fdc45f07f3e5cbf7b9531c94
                }
#endif
                OnRefreshEvent(new CurvyCGEventArgs(this, firstChanged));
            }
Reply
#6
You are welcome Guillaume

FindObjectsOfType indeed allocates a lot of memory, you are right on that one. I should ideally get rid of it (or use it less often), no doubt about that.

And that line you removed, you did well removing it. I already removed it in my unreleased code. The modification will be part of Curvy 8.0

Once Curvy 8 is released and the usual post-release work charge increase is over, I will start selecting the tasks for the next version. Reducing these loading times will be definitely considered.

If and when you feel like it, please leave a review for the asset, that helps a lot.
Have a nice day
Please consider leaving a review for Curvy, this helps immensely. Thank you.
Available for freelance work—feel free to reach out.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Rasterized Path Range issue proton 7 27 04-30-2024, 11:17 AM
Last Post: _Aka_
  I want to improve the performance of Variable Mix Shapes yanke 7 10 07-27-2023, 09:15 PM
Last Post: _Aka_
  Rotation issue with generator nicolaj.h.andersen@gmail.com 1 16 04-14-2023, 11:58 AM
Last Post: _Aka_
  BuildVolumeMesh issue tairoark 40 95 11-25-2022, 07:57 AM
Last Post: _Aka_

Forum Jump: