Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question LocalizationBehaviour.LateUpdate causing big slowdown

Discussion in 'Localization Tools' started by mrCharli3, Feb 23, 2023.

  1. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    976
    Hey,

    For some reason my game spikes when performing a specific action, so I decided to deep profile it, and turns out it's the Localization package using the resources. No real indication as to where or how. Any ideas?

    upload_2023-2-23_13-17-25.png
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,141
    That's releasing Addressables operations. I dont know why it would cause that though. It looks like it's coming from the ObjectPools which are not specific to the localization package. Could you please file a bug report so we can investigate? https://unity.com/releases/editor/qa/bug-reporting
    Also, try updating to the latest version 1.4.3 if you are not already using it.
     
  3. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    976
    I wont be filing a bug report since my Unity crashed whenever I try that, but I can try updating!

    If it helps, each time I perform the action, the localization issue increases, for example from 700ms to 1000ms to 1500ms, and so on.
     
  4. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    976
    Unfortunately updating didnt solve it. Usually it says what actually calls it but no trace so very hard to debug.
     
  5. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,141
    Can you share the project?
     
  6. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    976
    Im afraid not due to legal reasons, plus the project is huge 40gb+.
     
  7. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,141
    Does the issue happen in a new project? I'm afraid theres not much we can do without a bug report or a project with the issue. The call stack doesn't tell us why it's causing the performance issues.
     
  8. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    976
    Its becoming a bit unsustainable now, this is in a live game with 100k+ players on Steam, full of quite heavy operations and localization package uses 36% of CPU?

    For reference, we have 1000+ unoptimized AI walking around with RVO enabled and they use 16% CPU...

    Is there any way we can look at this together? I'm happy to set a short meeting. If this continues I don't really have any other choice than to use something from the asset store instead of your own solution, which is... disappointing.

    upload_2023-11-15_17-2-49.png
     
    Last edited: Nov 15, 2023
  9. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,141
    LocalizationBehaviour is responsible for returning operations back to object pools for reuse. So if you make 1000 calls to it in 1 frame then they will be returned a few frames later. This could be a sign that you need to manage your operations better. Are you using any custom code or just the LocalizationStringEvent component?
    One thing we could try and do is to time slice the release operation so it does not run in a single frame but spreads out to avoid spikes.
    We can meet to work through this although I don't think it will be necessary.
    Lets first look at how you are calling localization, ill look at making some changes to support time slicing and tell you how to customize the package to incorporate them.
     
  10. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,141
    Here are 2 changes you can apply:

    First, move the localization package folder out of the PackageCache and into the projects Packages folder. You will now be able to make changes, make sure you commit this to your source control.

    1) Apply throttling to the LocalizationBehaviour: throttling.patch
    2) Improve pool performance, especially in the Editor, this is a bigger change. pools.patch

    We will get both of these changes into our next release 1.5, this should be available before the end of the year.
     

    Attached Files:

    Last edited: Nov 15, 2023
  11. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    976
    Thank you very much for this, can you explain the process you have in mind when you say to "apply" these .txt files? How do I go about applying them?

    As for special operations, I do a lot of localization at runtime, no way around that, so the LocalizationStringEvent is only used for strings that never change.

    I use this helper class for translations at runtime:
    Code (CSharp):
    1. public static class Utils_Text
    2. {
    3.     public static StringTable GetStringTable()
    4.     {
    5.         return LocalizationSettings.StringDatabase.GetTable("stringTable", LocalizationSettings.SelectedLocale);
    6.     }
    7.  
    8.     public static string GetLocalizedString(string entryKey)
    9.     {
    10.         string result = "";
    11.  
    12.         try
    13.         {
    14.             result = GetStringTable().GetEntry(entryKey).GetLocalizedString();
    15.         }
    16.         catch
    17.         {
    18.             Debug.LogError("Could not find localization entry: " + entryKey);
    19.         }
    20.  
    21.         return result;
    22.     }
    23. }

    I realized now I can do some improvements in my end too, I added a cache for the string table:
    Code (CSharp):
    1. public static class Utils_Text
    2. {
    3.     public static StringTable stringTable;
    4.  
    5.     public static StringTable GetStringTable()
    6.     {
    7.         return LocalizationSettings.StringDatabase.GetTable("stringTable", LocalizationSettings.SelectedLocale);
    8.     }
    9.  
    10.     public static string GetLocalizedString(string entryKey)
    11.     {
    12.         string result = "";
    13.  
    14.         if(stringTable == null)
    15.         {
    16.             stringTable = GetStringTable();
    17.         }
    18.  
    19.         try
    20.         {
    21.             result = stringTable.GetEntry(entryKey).GetLocalizedString();
    22.         }
    23.         catch
    24.         {
    25.             Debug.LogError("Could not find localization entry: " + entryKey);
    26.         }
    27.  
    28.         return result;
    29.     }
    30. }
     
    Last edited: Nov 16, 2023
    karl_jones likes this.
  12. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,141
    Hi. They are patch files, you can apply them using various software.

    Caching the string table will likely solve the issue however if it does not then apply the suggested changes:

    I think the simplest thing would be to just apply the throttling, that should do enough.
    Replace the contents of LocalizationBehaviour.cs with:

    Code (csharp):
    1. using System.Collections.Generic;
    2. using System.Runtime.CompilerServices;
    3. using UnityEngine.ResourceManagement.AsyncOperations;
    4. using UnityEngine.ResourceManagement.Util;
    5.  
    6. namespace UnityEngine.Localization
    7. {
    8.    class LocalizationBehaviour : ComponentSingleton<LocalizationBehaviour>
    9.    {
    10.        Queue<(int frame, AsyncOperationHandle handle)> m_ReleaseQueue = new Queue<(int, AsyncOperationHandle)>();
    11.  
    12.        const long k_MaxMsPerUpdate = 10;
    13.        const bool k_DisableThrottling = false;
    14.  
    15.        protected override string GetGameObjectName() => "Localization Resource Manager";
    16.  
    17.        /// <summary>
    18.        /// To prevent you having to explicitly release operations, Unity does this automatically a frame after the operation is completed.
    19.        /// If you plan to keep hold of a reference, call <see cref="AsyncOperationHandle.Acquire"/>, and <see cref="AsyncOperationHandle.Release"/> when it's finished.
    20.        /// </summary>
    21.        /// <param name="handle"></param>
    22.        public static void ReleaseNextFrame(AsyncOperationHandle handle) => Instance.DoReleaseNextFrame(handle);
    23.  
    24.        [MethodImpl(MethodImplOptions.AggressiveInlining)]
    25.        static long TimeSinceStartupMs() => (long)(Time.realtimeSinceStartup * 1000.0f);
    26.  
    27.        void DoReleaseNextFrame(AsyncOperationHandle handle)
    28.        {
    29.            enabled = true;
    30.            m_ReleaseQueue.Enqueue((Time.frameCount, handle));
    31.        }
    32.  
    33.        void LateUpdate()
    34.        {
    35.            var currentFrame = Time.frameCount;
    36.            long currentTime = TimeSinceStartupMs();
    37.            long maxTime = currentTime + k_MaxMsPerUpdate;
    38.            while (m_ReleaseQueue.Count > 0 && m_ReleaseQueue.Peek().frame < currentFrame)
    39.            {
    40.                currentTime = TimeSinceStartupMs();
    41.                if (!k_DisableThrottling && currentTime >= maxTime)
    42.                {
    43.                    // We spent too much time on this frame, we break for now, we'll resume next frame
    44.                    break;
    45.                }
    46.  
    47.                var item = m_ReleaseQueue.Dequeue();
    48.                AddressablesInterface.SafeRelease(item.handle);
    49.            }
    50.  
    51.            if (m_ReleaseQueue.Count == 0)
    52.                enabled = false;
    53.        }
    54.  
    55.        public static void ForceRelease()
    56.        {
    57.            foreach(var r in Instance.m_ReleaseQueue)
    58.            {
    59.                AddressablesInterface.SafeRelease(r.handle);
    60.            }
    61.            Instance.m_ReleaseQueue.Clear();
    62.        }
    63.    }
    64. }
     
    Last edited: Nov 16, 2023
    mrCharli3 likes this.
  13. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    976
    Thanks a lot for the help :)
     
    karl_jones likes this.