Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

TextMesh Pro TextMesh Pro .text vs SetText/SetCharArray - significant performance differences

Discussion in 'UGUI & TextMesh Pro' started by shihab37, Jun 29, 2023.

  1. shihab37

    shihab37

    Joined:
    Jul 7, 2015
    Posts:
    28
    Edit: the performance difference is probably because .text doesn't update the TMP_Text object if the string has not changed but the SetText and SetCharArray functions always regenerate text.


    So I wanted to make some zero GC allocation text overlays and while I was able to achieve zero allocation using ZString, I noticed big performance difference between setting text via '.text' property and SetCharArray function. (ZString provides an extension method that sets TMP tex via SetCharArray to avoid conversion to string)
    So I created some separate tests and discovered that SetText(string) and SetText(stringBuilder) also have the same performance overheads as SetCharArray.


    Test Setup:
    - [Unity 23.1.1f1 + TMPro 3.0.6] and [Unity 23.1.1f1 + TMPro 3.2.0-pre.4]
    - A single TextMeshProUGUI object as an only child of an overlay canvas.
    - 30 lines of formatted text generated using StringBuilder.
    - Profiled in Editor and Android Builds

    [In these tests I didn't use ZString as I wanted to test TMPro in isolation so GC allocations in the results can be ignored.]

    Code:
    Code (CSharp):
    1. public class TMPTester : MonoBehaviour
    2. {
    3.     [SerializeField] private TextMeshProUGUI _tmp;
    4.  
    5.     private int intVar = 456;
    6.     private float floatVar = 0.8987f;
    7.     private double doubleVar = 78.788080;
    8.  
    9.     private StringBuilder _sb = new StringBuilder(500);
    10.  
    11.  
    12.     void Update() {
    13.  
    14.         _sb.Clear();
    15.         for (int i = 0; i < 30; i++) {
    16.             _sb.AppendFormat("Test string: {0} - {1:N2} - {2:00.###} - {3:F3}\n", intVar, floatVar, doubleVar, 0.0596);
    17.         }
    18.         _tmp.text = _sb.ToString();
    19.         //_tmp.SetText(_sb.ToString());
    20.         //_tmp.SetText(_sb);
    21.     }
    22. }
    Results:
    When assigning new string to .text property, there's no TMPro overhead in rebuilding the canvas. but when setting text using SetText(string), SetText(stringBuilder) and SetCharArray functions, the "TMP.GenerateText" consumes a huge (relatively) chunk of CPU frame time during canvas rebuild both in Editor and builds.

    Profiler screenshots:
    [_tmp.text = _sb.ToString();] Editor
    upload_2023-6-29_12-45-51.png
    [_tmp.text = _sb.ToString();] Android Dev Build
    upload_2023-6-29_12-44-43.png
    [_tmp.SetText(_sb.ToString());] Editor
    upload_2023-6-29_12-58-6.png
    [_tmp.SetText(_sb.ToString());] Android Build
    upload_2023-6-29_12-58-24.png
    [_tmp.SetText(_sb);] Android Build
    upload_2023-6-29_12-58-39.png


    Is there some kind of setting I am missing? or I'm making some mistake setting up TextMesh Pro in UI?
    Has anyone else ever noticed this difference in performance?
     
    Last edited: Jul 1, 2023
    CodeRonnie likes this.
  2. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    I have not encountered it personally, but I have a zero allocation string library that I will need to test for performance with TextMeshPro at some point. So, thank you for flagging these performance assessments. I'm not sure when I will have time to run corroborative testing of my own, but maybe in the next month or so I will get an opportunity to compare results. In fact I will have to, some time in the next few weeks, ensure that there are no rough edges for usage or compatibility with TMPro.TMP_Text.SetCharArray(char[]), although I don't predict any except adding some quality of life extension methods perhaps. Your profiler screenshots would be more informative to me if they were not in timeline view, but in the tree view where you could highlight the specific methods in question, showing their exact performance metrics.
     
  3. shihab37

    shihab37

    Joined:
    Jul 7, 2015
    Posts:
    28
    Never mind ... turns out my test setup was flawed :(:(
    This test code effectively generates a static string so .text property setter ignores unnecessary updates and the canvas is not rebuilt ... that's why I was not seeing "TMP.GenerateText" taking up any CPU time when setting text via .text property. However TMP text is always regenerated when setting via SetText or SetCharArray. I suppose that's why using .text is the recommended way. :)
    When I repeated the test using a string that changes every frame, all these methods of updating TMP text have the same performance.
     
    CodeRonnie likes this.
  4. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    Ahh, that's a good explanation, and good to know.
     
  5. shihab37

    shihab37

    Joined:
    Jul 7, 2015
    Posts:
    28
    @CodeRonnie Switchboard seems like an awesome product. I had been looking for a lightweight dependency injection framework for unity and this one has additional cool features as well. Will be keeping an eye out for its release :)
    Maybe we can add some checks to see if the string has actually changed before calling SetCharArray to get the same benefits as ".text" ? I don't know how helpful this would be in real world use cases though.
    P.S. I do have the profiler screenshots in Hierarchy view as well. I just didn't want to clutter the post unnecessarily. Let me know if you think they are still relevant/helpful and I will post them.
     
    CodeRonnie likes this.
  6. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    Oh, wow, thank you! That's genuinely the first compliment I've received! :)

    I think it should be out some time in August. The queue for the asset store is in the thousands, so I have to wait a while. I'm waiting until it is actually available to make any kind of announcement. The GitHub page linked in the feedback section has some estimates on release date. I still have a short list of tasks I'd like to do in the next few weeks. I'd like to patch in a few hotfixes before it gets to the front of the queue, and I need to keep working on the docs and samples when I can. I am going to try to add a full screen video player sample that shows a combination of prefabs in the scene, classes at the composition root, and loading in prefabs from the composition root, that all work nicely together and handle their single responsibility.

    Cheers for the compliment.
     
    shihab37 likes this.
  7. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    Oh, and I like the idea of adding an extension method to TMPro to check whether the char[] being passed has changed before actually calling the underlying method. Then you wouldn't have to think about it. I could easily add that to Switchboard.
     
  8. shihab37

    shihab37

    Joined:
    Jul 7, 2015
    Posts:
    28
    I haven't had the chance to read the whole documentation yet but I like what I have read so far. Especially the idea of a composition root (which I guess most of us have had to implement at times in one form or another) and keeping the dependency injection minimal and really simple. I also like your documentation style where you first explain a concept/feature in detail along with the explanation of why you thought it was needed before describing how it is implemented in your product.
    I probably shouldn't turn this thread into a discussion about Switchboard though :D
    Good luck with the release.

    Yes that'd be really great
     
    CodeRonnie likes this.
  9. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    Yeah, it's really just a replacement for singletons, in the end. I just did a lot of research on dependency injection to see what all the fuss was about, and this is what I ended up with.
     
    shihab37 likes this.